Commit f4a50b83 authored by Jérome Perrin's avatar Jérome Perrin

Merge remote-tracking branch 'upstream/master' into zope4py3

parents 6c24fae6 ed138c6e
...@@ -9,29 +9,6 @@ How to deploy from scratch ...@@ -9,29 +9,6 @@ How to deploy from scratch
2. Install ors playbook 2. Install ors playbook
3. Deploy this SR 3. Deploy this SR
## Generated buildout configurations and json input schemas
Since there are multiple ors-amarisoft softwares releases and software types, the following files are
generated with jinja2 templates with the render-templates script before being pushed to gitlab:
* instance-tdd-enb-input-schema.json
* instance-fdd-enb-input-schema.json
* software-fdd.cfg
* software-tdd.cfg.json
* instance-fdd-ue-nr-input-schema.json
* instance-tdd-gnb-input-schema.json
* instance-tdd-ue-nr-input-schema.json
* test/testFDD.py
* test/testTDD.py
* software-tdd.cfg
* instance-tdd-ue-lte-input-schema.json
* instance-fdd-gnb-input-schema.json
* software-fdd.cfg.json
* instance-fdd-ue-lte-input-schema.json
These files should not be modified directly, and the render-templates scripts should be run along
with update-hash before each commit.
## Services ## Services
We run 2 binaries from Amarisoft LTE stack: We run 2 binaries from Amarisoft LTE stack:
......
...@@ -16,19 +16,19 @@ ...@@ -16,19 +16,19 @@
[template] [template]
filename = instance.cfg filename = instance.cfg
md5sum = fa81cd744e5a9382aa203c3777adc3a8 md5sum = 22e06207fab996bcc1c26992106618ab
[template-ors] [template-ors]
filename = instance-ors.cfg filename = instance-ors.cfg
md5sum = 56a2c2b8245e86f3a8ed2eebeb8e88d9 md5sum = f5c76c3443b75569eb18503dce38e783
[slaplte.jinja2] [slaplte.jinja2]
_update_hash_filename_ = slaplte.jinja2 _update_hash_filename_ = slaplte.jinja2
md5sum = 566efd38f12e6d42769399f421e77d6c md5sum = 871ade334f445e22d6cb473e4d4e3522
[ru_amarisoft-stats.jinja2.py] [ru_amarisoft-stats.jinja2.py]
_update_hash_filename_ = ru/amarisoft-stats.jinja2.py _update_hash_filename_ = ru/amarisoft-stats.jinja2.py
md5sum = c4d5e9fcf460d88bc2b4bcfbdfe554f7 md5sum = 674dcc250c0b6bb43d8546624552fc5d
[ru_amarisoft-rf-info.jinja2.py] [ru_amarisoft-rf-info.jinja2.py]
_update_hash_filename_ = ru/amarisoft-rf-info.jinja2.py _update_hash_filename_ = ru/amarisoft-rf-info.jinja2.py
...@@ -36,19 +36,19 @@ md5sum = ab666fdfadbfc7d8a16ace38d295c883 ...@@ -36,19 +36,19 @@ md5sum = ab666fdfadbfc7d8a16ace38d295c883
[ru_libinstance.jinja2.cfg] [ru_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/libinstance.jinja2.cfg _update_hash_filename_ = ru/libinstance.jinja2.cfg
md5sum = 30c262a427de2132d6d66d9fb3597426 md5sum = 2dda7713832be83d94522c7abb4901f9
[ru_sdr_libinstance.jinja2.cfg] [ru_sdr_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sdr/libinstance.jinja2.cfg _update_hash_filename_ = ru/sdr/libinstance.jinja2.cfg
md5sum = de71c63b8df940207409de7e948f7c8c md5sum = b7906ca3a6b17963f78f680fc0842b74
[ru_lopcomm_libinstance.jinja2.cfg] [ru_lopcomm_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/lopcomm/libinstance.jinja2.cfg _update_hash_filename_ = ru/lopcomm/libinstance.jinja2.cfg
md5sum = 71508d94a47db493f30af30188c48d64 md5sum = 41ea7248b54ea893cb83a01655018711
[ru_sunwave_libinstance.jinja2.cfg] [ru_sunwave_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sunwave/libinstance.jinja2.cfg _update_hash_filename_ = ru/sunwave/libinstance.jinja2.cfg
md5sum = c855ee7a6132899eb53b8d80ec27701a md5sum = bc5d82b8737b6990674b280ef2774be7
[ru_lopcomm_ncclient_common.py] [ru_lopcomm_ncclient_common.py]
_update_hash_filename_ = ru/lopcomm/ncclient_common.py _update_hash_filename_ = ru/lopcomm/ncclient_common.py
...@@ -76,7 +76,11 @@ md5sum = 2b08bb666c5f3ab287cdddbfdb4c9249 ...@@ -76,7 +76,11 @@ md5sum = 2b08bb666c5f3ab287cdddbfdb4c9249
[ru_tapsplit] [ru_tapsplit]
_update_hash_filename_ = ru/tapsplit _update_hash_filename_ = ru/tapsplit
md5sum = 2b8b57c5771b2a2203c0e7767e629e55 md5sum = 700aab566289619fb83ac6f3b085d983
[ru_xbuildout.py]
_update_hash_filename_ = ru/xbuildout.py
md5sum = a51171f926edd315a52841c2e7eb9fb7
[ru_capdo.c] [ru_capdo.c]
_update_hash_filename_ = ru/capdo.c _update_hash_filename_ = ru/capdo.c
...@@ -84,19 +88,19 @@ md5sum = 52da9fe3a569199e35ad89ae1a44c30e ...@@ -84,19 +88,19 @@ md5sum = 52da9fe3a569199e35ad89ae1a44c30e
[template-enb] [template-enb]
_update_hash_filename_ = instance-enb.jinja2.cfg _update_hash_filename_ = instance-enb.jinja2.cfg
md5sum = c8096440bfc2a1ed0e2821ef71e0bd1c md5sum = f54bdbb308aee424b07ede8b551cfe5b
[template-ors-enb] [template-ors-enb]
_update_hash_filename_ = instance-ors-enb.jinja2.cfg _update_hash_filename_ = instance-ors-enb.jinja2.cfg
md5sum = f1e6e2fb8854482d570fc3eee4935f84 md5sum = 601d6237059fa665d3f3ffb6a78ad9ca
[template-core-network] [template-core-network]
_update_hash_filename_ = instance-core-network.jinja2.cfg _update_hash_filename_ = instance-core-network.jinja2.cfg
md5sum = c807be73b9304f5a4c7483a3776bbc17 md5sum = 9402b750221765b6b124cf5ecb3e520c
[template-ue] [template-ue]
_update_hash_filename_ = instance-ue.jinja2.cfg _update_hash_filename_ = instance-ue.jinja2.cfg
md5sum = d8153dd5e0978afea018498b29f06fd5 md5sum = 812a43458c21f7d0cdb2141515a236ae
[template-obsolete] [template-obsolete]
_update_hash_filename_ = instance-obsolete.jinja2.cfg _update_hash_filename_ = instance-obsolete.jinja2.cfg
...@@ -108,19 +112,19 @@ md5sum = dcaac06553a3222b14c0013a13f4a149 ...@@ -108,19 +112,19 @@ md5sum = dcaac06553a3222b14c0013a13f4a149
[enb.jinja2.cfg] [enb.jinja2.cfg]
filename = config/enb.jinja2.cfg filename = config/enb.jinja2.cfg
md5sum = a7f898b48b15992b2c4a64a925f007aa md5sum = 30a26b975100b1af8937dfe3a7f5f496
[drb_lte.jinja2.cfg] [drb_lte.jinja2.cfg]
filename = config/drb_lte.jinja2.cfg filename = config/drb_lte.jinja2.cfg
md5sum = 6c8bdb0ce1d2bdd846a87aa6c5204a9c md5sum = 01eb971e2ff580da52291138495a81ca
[drb_nr.jinja2.cfg] [drb_nr.jinja2.cfg]
filename = config/drb_nr.jinja2.cfg filename = config/drb_nr.jinja2.cfg
md5sum = 84d3cef8fc7f1c2aed7c348d500f5636 md5sum = 282b11d7b72b01b8325df4632d82b84d
[sib23.jinja2.asn] [sib23.jinja2.asn]
filename = config/sib23.jinja2.asn filename = config/sib23.jinja2.asn
md5sum = 0d709fafde394dc05441d110c2e41858 md5sum = 959523597e29b048e45ebf58f7ea4c5b
[mme.jinja2.cfg] [mme.jinja2.cfg]
filename = config/mme.jinja2.cfg filename = config/mme.jinja2.cfg
...@@ -132,7 +136,7 @@ md5sum = f167b4be5e327b276b42267e0678f577 ...@@ -132,7 +136,7 @@ md5sum = f167b4be5e327b276b42267e0678f577
[ru_dnsmasq.jinja2.cfg] [ru_dnsmasq.jinja2.cfg]
_update_hash_filename_ = ru/dnsmasq.jinja2.cfg _update_hash_filename_ = ru/dnsmasq.jinja2.cfg
md5sum = 9bd5b08f23640f71ad109d186d060f2d md5sum = 95f4f8fb85e0480eb3e9059b9db26540
[ims.jinja2.cfg] [ims.jinja2.cfg]
filename = config/ims.jinja2.cfg filename = config/ims.jinja2.cfg
...@@ -140,7 +144,7 @@ md5sum = 36281b03597252cf75169417d02fc28c ...@@ -140,7 +144,7 @@ md5sum = 36281b03597252cf75169417d02fc28c
[ue.jinja2.cfg] [ue.jinja2.cfg]
filename = config/ue.jinja2.cfg filename = config/ue.jinja2.cfg
md5sum = 1d55e896236f7ee08a10cd58182a9a76 md5sum = 62291a11fd36a42464901cdc81338687
[ru_lopcomm_CreateProcessingEle.jinja2.xml] [ru_lopcomm_CreateProcessingEle.jinja2.xml]
_update_hash_filename_ = ru/lopcomm/CreateProcessingEle.jinja2.xml _update_hash_filename_ = ru/lopcomm/CreateProcessingEle.jinja2.xml
...@@ -148,7 +152,7 @@ md5sum = e435990eb0a0d4be41efa9bd16dce09b ...@@ -148,7 +152,7 @@ md5sum = e435990eb0a0d4be41efa9bd16dce09b
[ru_lopcomm_cu_config.jinja2.xml] [ru_lopcomm_cu_config.jinja2.xml]
_update_hash_filename_ = ru/lopcomm/cu_config.jinja2.xml _update_hash_filename_ = ru/lopcomm/cu_config.jinja2.xml
md5sum = 09123ad68c6d8e7e4e201bcc2ab331c6 md5sum = 346c911e1ac5e5001a39c8926b44c91e
[software.cfg.html] [software.cfg.html]
_update_hash_filename_ = gadget/software.cfg.html _update_hash_filename_ = gadget/software.cfg.html
......
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Cell. Common properties",
"type": "object",
"required": [
"cell_type",
"rf_mode",
"pci",
"cell_id",
"bandwidth",
"ru"
],
"properties": {
"cell_type": {
"type": "string",
"options": { "hidden": true }
},
"cell_kind": {
"type": "string",
"const": "enb",
"template": "enb",
"options": { "hidden": true }
},
"rf_mode": {
"title": "RF mode",
"description": "Mode for TX/RX radio multiplexing: Frequency- or Time- Domain Division",
"type": "string",
"enum": ["fdd", "tdd"],
"propertyOrder": 101
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID",
"type": "integer"
},
"cell_id": {
"title": "Cell ID",
"description": "Cell ID",
"type": "string"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number"
},
"root_sequence_index": {
"title": "Root Sequence Index",
"type": "integer"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"ru": {
"$ref": "#/$defs/ru-of-cell",
"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" }
]
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Cell",
"type": "object",
"oneOf": [
{ "$ref": "../cell/lte/input-schema.json" },
{ "$ref": "../cell/nr/input-schema.json" }
]
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "LTE Cell",
"type": "object",
"required": [
"cell_type",
"rf_mode",
"pci",
"cell_id",
"bandwidth",
"ru",
"dl_earfcn",
"tac"
],
"properties": {
"$ref": "../../cell/common.json#/properties",
"cell_type": {
"$ref": "#/properties/cell_type",
"const": "lte",
"template": "lte"
},
"tdd_ul_dl_config": {
"title": "TDD Configuration",
"type": "string",
"enum": [
"[Configuration 2] 5ms 2UL 6DL (default)",
"[Configuration 6] 5ms 5UL 3DL (maximum uplink)"
],
"default": "[Configuration 2] 5ms 2UL 6DL (default)",
"options": {
"dependencies": {
"rf_mode": "tdd"
}
}
},
"bandwidth": {
"$ref": "#/properties/bandwidth",
"enum": [
1.4,
3,
5,
10,
15,
20
]
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "integer"
},
"ul_earfcn": {
"title": "UL EARFCN",
"description": "Uplink E-UTRA Absolute Radio Frequency Channel Number of the cell. By default a frequency corresponding to dl_earfcn is chosen.",
"type": "integer"
},
"tac": {
"title": "Tracking Area Code",
"description": "Tracking Area Code in hexadecimal representation (range 0x0000 to 0xffff)",
"type": "string"
},
"root_sequence_index": {
"$ref": "#/properties/root_sequence_index",
"description": "Range: 0 to 837. Set the PRACH root sequence index (SIB2.rootSequenceIndex field). It must be different for each neighbour cell operating on the same frequency and sharing the same PRACH configuration.",
"default": 204
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "NR Cell",
"type": "object",
"required": [
"cell_type",
"rf_mode",
"pci",
"cell_id",
"bandwidth",
"ru",
"dl_nr_arfcn",
"nr_band"
],
"properties": {
"$ref": "../../cell/common.json#/properties",
"cell_type": {
"$ref": "#/properties/cell_type",
"const": "nr",
"template": "nr"
},
"tdd_ul_dl_config": {
"title": "TDD Configuration",
"type": "string",
"enum": [
"5ms 2UL 7DL 4/6 (default)",
"2.5ms 1UL 3DL 2/10",
"5ms 8UL 1DL 2/10 (maximum uplink)"
],
"default": "5ms 2UL 7DL 4/6 (default)",
"options": {
"dependencies": {
"rf_mode": "tdd"
}
}
},
"bandwidth": {
"$ref": "#/properties/bandwidth"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "integer"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "integer"
},
"ul_nr_arfcn": {
"title": "UL NR ARFCN",
"description": "Uplink NR Absolute Radio Frequency Channel Number of the cell. By default a frequency corresponding to dl_nr_arfcn and nr_band is chosen.",
"type": "integer"
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR Absolute Radio Frequency Channel Number of the cell. If set it must be an element of global synchronization raster and be at offset from center DL frequency that aligns with SSB subcarrier spacing of selected band. By default a valid frequency nearby dl_nr_arfcn is chosen.",
"type": "integer"
},
"ssb_pos_bitmap": {
"title": "SSB Position Bitmap",
"description": "SSB position bitmap in bits (4, 8 or 64 bits depending on the DL frequency).",
"type": "string",
"default": "10000000"
},
"root_sequence_index": {
"$ref": "#/properties/root_sequence_index",
"description": "Range 0 to 837 for PRACH format up to 3, 0 to 137 otherwise. prach-RootSequenceIndex parameter. It must be different for each neighbour cell operating on the same frequency and sharing the same PRACH configuration.",
"default": 1
}
},
"$defs": {
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by Cell instantiation (stub)",
"type": "object",
"properties": {}
}
// DRB configuration for LTE cell. {%- set B = xbuildout.encode -%}
// DRB configuration for LTE cell {{ B(cell_ref) }} @ {{ B(ru_ref) }}.
// DRB configuration vary in beteen FDD and TDD modes. // DRB configuration vary in beteen FDD and TDD modes.
{% set T_REORDERING = {'fdd': 35, 'tdd': 65} [rf_mode] %} {% set T_REORDERING = {'fdd': 35, 'tdd': 65} [cell.rf_mode] %}
// {{ rf_mode | upper }} T_REORDERING={{ T_REORDERING }} // {{ cell.rf_mode | upper }} T_REORDERING={{ T_REORDERING }}
[ [
{ {
......
// DRB configuration for NR cell. {%- set B = xbuildout.encode -%}
// DRB configuration for NR cell {{ B(cell_ref) }} @ {{ B(ru_ref) }}.
[ [
{ {
......
{%- import 'slaplte.jinja2' as slaplte with context %} {%- import 'slaplte.jinja2' as slaplte with context %}
{%- set B = slaplte.B %}
{%- 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 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 cell_list = {} %} {%- set iru_dict = {} %}
{%- do slaplte.load_cell(cell_list) %} {%- set icell_dict = {} %}
{%- set ipeer_dict = {} %}
{%- set ipeercell_dict = {} %}
{%- do slaplte.load_iru_and_icell(iru_dict, icell_dict, icell_kind='enb') %}
{%- do slaplte.load_ipeer(ipeer_dict) %}
{%- do slaplte.load_ipeercell(ipeercell_dict) %}
{%- do slaplte.check_loaded_everything() %}
{%- endif %} {%- endif %}
{#- do_lte/do_nr indicate whether we have LTE or NR cell #} {#- do_lte/do_nr indicate whether we have LTE and/or NR cells
{%- do assert(do_lte or do_nr) %} icell_dict_lte/icell_dict_nr keep LTE/NR parts of icell_dict registry #}
{%- do assert(not (do_lte and do_nr)) %} {%- set icell_dict_lte = dict(icell_dict|dictsort | selectattr('1._.cell_type', '==', 'lte')) %}
{%- set icell_dict_nr = dict(icell_dict|dictsort | selectattr('1._.cell_type', '==', 'nr' )) %}
{%- set do_lte = len(icell_dict_lte) > 0 %}
{%- set do_nr = len(icell_dict_nr) > 0 %}
{#- ru and cell are namespace objects that hold Radio Unit and Cell related parameters #} {#- handover_config emits handover configuration for specified cell #}
{%- set ru = namespace(ru_type=ru_type) %} {%- macro handover_config(cell_ref) %}
{%- set cell = namespace() %}
{#- handover_config emits handover configuration #}
{%- macro handover_config() %}
ncell_list: [ ncell_list: [
// Intra-ENB HO
{%- for cell2_ref, icell2 in icell_dict|dictsort %}
{%- set cell2 = icell2['_'] %}
{%- if cell2_ref != cell_ref %} {#- NOTE: HO to both LTE and NR #}
{%- set ru2_ref = J(jcell_ru_ref(icell2, icell_dict)) %}
{%- set iru2 = iru_dict[ru2_ref] %}
{%- set ru2 = iru2['_'] %}
{
{%- if cell2.cell_type == 'lte' %}
rat: "eutra",
cell_id: {{ slapparameter_dict.enb_id }}{{ cell2.cell_id.removeprefix('0x') }}, // -> {{ B(cell2_ref) }}
n_id_cell: {{ cell2.pci }},
dl_earfcn: {{ cell2.dl_earfcn }},
tac: {{ cell2.tac }},
allowed_meas_bandwidth: {{ jlte_n_rb_dl(cell2.bandwidth) }},
antenna_port_1: {{ (ru2.n_antenna_dl > 1) | tojson }},
{%- elif cell2.cell_type == 'nr' %}
rat: "nr",
cell_id: {{ cell2.cell_id }}, // -> {{ B(cell2_ref) }}
{%- else %}
{%- do bug('unreachable') %}
{%- endif %}
},
{%- endif %}
{%- endfor %}
// Inter-ENB HO // Inter-ENB HO
{%- for _, ncell in slapparameter_dict.get('ncell_list', {})|dictsort %} {#- 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
put them as peers here #}
{%- for peercell_ref, ipeercell in ipeercell_dict|dictsort %}
{%- set ncell = ipeercell['_'] %}
{ {
{%- if do_lte %} {%- if ncell.cell_type == 'lte' %}
rat: "eutra", rat: "eutra",
n_id_cell: {{ ncell.get('pci', '') }}, cell_id: {{ ncell.e_cell_id }}, // -> {{ B(peercell_ref) }}
dl_earfcn: {{ ncell.get('dl_earfcn', '') }}, n_id_cell: {{ ncell.pci }},
cell_id: {{ ncell.get('cell_id', '') }}, dl_earfcn: {{ ncell.dl_earfcn }},
tac: {{ ncell.get('tac', 1) }}, tac: {{ ncell.tac }},
{%- elif do_nr %} {#- TODO: consider extending peer/cell/lte with
.allowed_meas_bandwidth and .antenna_port_1 #}
allowed_meas_bandwidth: {{ jlte_n_rb_dl(1.4) }}, // (minimum possible bw)
antenna_port_1: false, // (conservative stub)
{%- elif ncell.cell_type == 'nr' %}
rat: "nr", rat: "nr",
dl_nr_arfcn: {{ ncell.get('dl_nr_arfcn', '') }}, nr_cell_id: {{ ncell.nr_cell_id }}, // -> {{ B(peercell_ref) }}
ssb_nr_arfcn: {{ ncell.get('ssb_nr_arfcn', '') }}, gnb_id_bits: {{ ncell.gnb_id_bits }},
ul_nr_arfcn: {{ ncell.get('dl_nr_arfcn', '') }}, n_id_cell: {{ ncell.pci }},
n_id_cell: {{ ncell.get('pci', '') }}, dl_nr_arfcn: {{ ncell.dl_nr_arfcn }},
gnb_id_bits: {{ ncell.get('gnb_id_bits', '') }}, band: {{ ncell.nr_band }},
nr_cell_id: {{ ncell.get('nr_cell_id', '') }}, ssb_nr_arfcn: {{ ncell.ssb_nr_arfcn }},
tac: {{ ncell.get('tac', 1) }}, ul_nr_arfcn: {{ ncell.ul_nr_arfcn }},
band: {{ ncell.get('nr_band', '') }}, tac: {{ ncell.tac }},
ssb_subcarrier_spacing: 30, ssb_subcarrier_spacing: 30,
ssb_period: 20, ssb_period: 20,
ssb_offset: 0, ssb_offset: 0,
...@@ -63,39 +103,35 @@ ...@@ -63,39 +103,35 @@
10: 50, 10: 50,
15: 75, 15: 75,
20: 100} %} 20: 100} %}
{{- _[float(bandwidth.removesuffix(' MHz'))] | tojson }} {{- _[bandwidth] | tojson }}
{%- endmacro %} {%- endmacro %}
{#- jhostport splits address into (host,port) pair. #}
{%- if do_lte %} {%- macro jhostport(addr) %}
{%- if slapparameter_dict.get('tdd_ul_dl_config', '[Configuration 2] 5ms 2UL 6DL (default)') == '[Configuration 2] 5ms 2UL 6DL (default)' %} {%- set _ = namespace() %}
{%- set tdd_config = 2 %} {%- if ':' not in addr %}
{%- elif slapparameter_dict.get('tdd_ul_dl_config', '[Configuration 2] 5ms 2UL 6DL (default)') == '[Configuration 6] 5ms 5UL 3DL (maximum uplink)' %} {%- set _.host = addr %}
{%- set tdd_config = 6 %} {%- set _.port = None %}
{%- endif %} {%- else %}
{%- endif %} {%- set head, tail = addr.rsplit(':', 1) %}
{%- if ':' not in head %}
{%- if do_nr %} {%- set _.host = head %}
{%- if slapparameter_dict.get('tdd_ul_dl_config', '5ms 2UL 7DL 4/6 (default)') == '5ms 2UL 7DL 4/6 (default)' %} {%- set _.port = tail %}
{%- set tdd_config = 1 %} {%- else %}
{%- elif slapparameter_dict.get('tdd_ul_dl_config', '5ms 2UL 7DL 4/6 (default)') == '2.5ms 1UL 3DL 2/10' %} {%- if addr.startswith('[') %}
{%- set tdd_config = 2 %} {%- set _.host = addr[1:addr.index(']')] %}
{%- elif slapparameter_dict.get('tdd_ul_dl_config', '5ms 2UL 7DL 4/6 (default)') == '5ms 8UL 1DL 2/10 (maximum uplink)' %} {%- set _.port = tail %}
{%- set tdd_config = 3 %} {%- else %}
{%- set _.host = addr %}
{%- set _.port = None %}
{%- endif %} {%- endif %}
{%- endif %} {%- endif %}
{%- if do_lte %}
{%- set cell.bandwidth = slapparameter_dict.get('bandwidth', slap_configuration['configuration.default_lte_bandwidth']) %}
{%- endif %} {%- endif %}
{{- (_.host, _.port) | tojson }}
{%- endmacro -%}
{%- set ru.n_antenna_dl = slapparameter_dict.get('n_antenna_dl', int(slap_configuration['configuration.default_n_antenna_dl'])) %}
{% if ru.ru_type == "m2ru" %}
{%- set ru.n_antenna_ul = slapparameter_dict.get('n_antenna_ul', 1) %}
{% else %}
{%- set ru.n_antenna_ul = slapparameter_dict.get('n_antenna_ul', int(slap_configuration['configuration.default_n_antenna_ul'])) %}
{% endif %}
{#- start of the config -#}
{ {
log_options: "all.level=error,all.max_size=0,nas.level=debug,nas.max_size=1,s1ap.level=debug,s1ap.max_size=1,x2ap.level=debug,x2ap.max_size=1,rrc.level=debug,rrc.max_size=1,ngap.level=debug,ngap.max_size=1,xnap.level=debug,xnap.max_size=1, log_options: "all.level=error,all.max_size=0,nas.level=debug,nas.max_size=1,s1ap.level=debug,s1ap.max_size=1,x2ap.level=debug,x2ap.max_size=1,rrc.level=debug,rrc.max_size=1,ngap.level=debug,ngap.max_size=1,xnap.level=debug,xnap.max_size=1,
{%- if slapparameter_dict.get('log_phy_debug', False) -%} {%- if slapparameter_dict.get('log_phy_debug', False) -%}
...@@ -106,225 +142,164 @@ ...@@ -106,225 +142,164 @@
,file.rotate=1G,file.path=/dev/null", ,file.rotate=1G,file.path=/dev/null",
log_filename: "{{ directory['log'] }}/enb.log", log_filename: "{{ directory['log'] }}/enb.log",
{% if ru.ru_type == "lopcomm" %} {# instantiate radio units #}
rf_driver: { {{ slaplte.ru_config(iru_dict, slapparameter_dict) }}
{%- if slapparameter_dict.get('disable_sdr', False) %}
name: "dummy",
{%- else %}
name: "sdr",
{%- endif %}
args: "dev0=
{%- for i, k in enumerate(cell_list) %}
{%- set cpri_port = cell_list[k].cpri_port_number %}
{%- if i != 0 -%}
,
{%- endif -%}
/dev/sdr{{ slapparameter_dict.get('sdr_number', 0) }}@{{ cpri_port }}
{%- endfor -%}
",
cpri_mapping: "hw",
{%- set cpri_mult = slapparameter_dict.get('cpri_mult', 16) %}
cpri_mult: "
{%- for i, k in enumerate(cell_list) %}
{%- if i != 0 -%}
,
{%- endif -%}
{{ cpri_mult }}
{%- endfor -%}
",
cpri_rx_delay: "
{%- for i, k in enumerate(cell_list) %}
{%- if i != 0 -%}
,
{%- endif -%}
{{ cell_list[k].get('cpri_rx_delay', 0) }}
{%- endfor -%}
",
cpri_tx_delay: "
{%- for i, k in enumerate(cell_list) %}
{%- if i != 0 -%}
,
{%- endif -%}
{{ cell_list[k].get('cpri_tx_delay', 0) }}
{%- endfor -%}
",
cpri_tx_dbm: "
{%- for i, k in enumerate(cell_list) %}
{%- if i != 0 -%}
,
{%- endif -%}
{{ cell_list[k].get('cpri_tx_dbm', 0) }}
{%- endfor -%}
",
ifname: "{{ cell_list.values() | map(attribute='_tap') | join(',') }}",
},
tx_gain: 0,
rx_gain: 0,
{% elif ru.ru_type == "m2ru" %}
rf_driver: {
{%- if slapparameter_dict.get('disable_sdr', False) %}
name: "dummy",
{%- else %}
name: "sdr",
{%- endif %}
args: "dev0=/dev/sdr0@0",
cpri_mapping: "bf1",
cpri_mult: 16,
cpri_rx_delay: 11.0,
cpri_tx_delay: 0,
ifname: "cpri0",
cpri_tx_dbm: 42.0,
},
tx_gain: 0,
rx_gain: 0,
{% elif ors %}
rf_driver: {
{%- if slapparameter_dict.get('disable_sdr', False) %}
name: "dummy",
{%- else %}
name: "sdr",
{%- endif %}
args: "dev0=/dev/sdr0",
{% if slapparameter_dict.get('gps_sync', False) %}
sync: "gps",
{% endif %}
rx_antenna:"tx_rx",
tdd_tx_mod: 1,
},
tx_gain: {{ tx_gain }},
rx_gain: {{ rx_gain }},
{% endif %}
{%- if slapparameter_dict.get('websocket_password', '') %} {%- if slapparameter_dict.get('websocket_password', '') %}
com_addr: "[{{ gtp_addr_v6 }}]:{{ slap_configuration['configuration.com_ws_port'] }}", com_addr: "[{{ gtp_addr_v6 }}]:{{ slapparameter_dict.com_ws_port }}",
com_auth: { com_auth: {
password: "{{ slapparameter_dict['websocket_password'] }}", password: "{{ slapparameter_dict['websocket_password'] }}",
}, },
{%- else %} {%- else %}
com_addr: "{{ slap_configuration['configuration.com_addr'] }}:{{ slap_configuration['configuration.com_ws_port'] }}", com_addr: "{{ slapparameter_dict.com_addr }}:{{ slapparameter_dict.com_ws_port }}",
{%- endif %} {%- endif %}
{%- if do_lte %} {% if do_lte %}
// LTE core network // LTE core network
mme_list: [ mme_list: [
{% if slapparameter_dict.get('mme_list', '') %} {%- for _, mme in slapparameter_dict.mme_list |dictsort %}
{%- for i, k in enumerate(slapparameter_dict['mme_list']) %}
{%- if i == 0 %}
{
{%- else -%}
, {
{%- endif %}
mme_addr: "{{ slapparameter_dict['mme_list'][k]['mme_addr'] }}",
}
{%- endfor -%}
{% else %}
{ {
mme_addr: "{{ slap_configuration['configuration.mme_addr'] }}", mme_addr: "{{ mme['mme_addr'] }}",
}, },
{% endif %} {%- endfor %}
], ],
{%- endif %} {%- endif %}
{%- if do_nr %} {% if do_nr %}
// NR core network // NR core network
amf_list: [ amf_list: [
{% if slapparameter_dict.get('amf_list', '') %} {%- for _, amf in slapparameter_dict.amf_list |dictsort %}
{%- for i, k in enumerate(slapparameter_dict['amf_list']) %}
{%- if i == 0 %}
{
{%- else -%}
, {
{%- endif %}
amf_addr: "{{ slapparameter_dict['amf_list'][k]['amf_addr'] }}",
}
{%- endfor -%}
{% else %}
{ {
amf_addr: "{{ slap_configuration['configuration.amf_addr'] }}", amf_addr: "{{ amf['amf_addr'] }}",
}, },
{% endif %} {%- endfor %}
], ],
{%- endif %} {%- endif %}
{% if slapparameter_dict.get('mme_list', '') or slapparameter_dict.get('amf_list', '') %} {#- listen-address for GTP-U - either explicitly given, or autodetect #}
{% if slapparameter_dict.get('gtp_addr') %} {%- if slapparameter_dict.get('gtp_addr') %}
gtp_addr: "{{ slapparameter_dict.get('gtp_addr') }}", gtp_addr: "{{ slapparameter_dict.gtp_addr }}",
{% else %} {%- else %}
{% if slapparameter_dict.get('use_ipv4', False) %} {#- use loopback if address of core network is on loopback as well #}
gtp_addr: "{{ gtp_addr_v6 }}", {%- set vcore = [] %}
{% else %} {%- if do_lte %}
{%- do vcore.extend(slapparameter_dict.mme_list |dictsort |map(attribute='1.mme_addr')) %}
{%- endif %}
{%- if do_nr %}
{%- do vcore.extend(slapparameter_dict.amf_list |dictsort |map(attribute='1.amf_addr')) %}
{%- endif %}
{#- remove optional :port from addresses and see if they are on loopback #}
{%- set vip = [] %}
{%- for a in vcore %}
{%- set _ = namespace() %}
{%- set _.ip = J(jhostport(a))[0] %}
{%- set _.islo = netaddr.IPAddress(_.ip).is_loopback() %}
{%- do vip.append(_) %}
{%- endfor %}
{%- if len(vip) > 0 and all(vip |map(attribute='islo')) %}
gtp_addr: "{{ gtp_addr_lo }}",
{%- else %}
{#- core is external - use external ipv4/ipv6 #}
{%- if slapparameter_dict.use_ipv4 %}
gtp_addr: "{{ gtp_addr_v4 }}", gtp_addr: "{{ gtp_addr_v4 }}",
{% endif %} {%- else %}
{% endif %} gtp_addr: "{{ gtp_addr_v6 }}",
{% else %} {%- endif %}
gtp_addr: "{{ slap_configuration['configuration.gtp_addr'] }}", {%- endif %}
{% endif %} {%- endif %}
{#- X2/Xn peers
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
depending on whether LTE and/or NR cells are there add X2 and/or Xn peers #}
{%- if do_lte %}
x2_peers: {{ ipeer_dict|dictsort | selectattr('1._.peer_type', '==', 'lte')
| map(attribute='1._.x2_addr')
| list | tojson }},
{%- endif %}
{%- if do_nr %} {%- if do_nr %}
{% if slapparameter_dict.get('xn_peers', '') %} xn_peers: {{ ipeer_dict|dictsort | selectattr('1._.peer_type', '==', 'nr')
xn_peers: [ | map(attribute='1._.xn_addr')
{%- for k in slapparameter_dict['xn_peers'] -%} | list | tojson }},
"{{ slapparameter_dict['xn_peers'][k]['xn_addr'] }}",
{%- endfor -%}
],
{% endif %}
{%- endif %} {%- endif %}
{%- if do_lte %} {%- if do_lte %}
enb_id: {{ slapparameter_dict.get('enb_id', '0x1A2D0') }}, enb_id: {{ slapparameter_dict.enb_id }},
{%- endif %} {%- endif %}
{%- if do_nr %} {%- if do_nr %}
gnb_id_bits: {{ slapparameter_dict.get('gnb_id_bits', 28) }}, gnb_id_bits: {{ slapparameter_dict.gnb_id_bits }},
gnb_id: {{ slapparameter_dict.get('gnb_id', '0x12345') }}, gnb_id: {{ slapparameter_dict.gnb_id }},
en_dc_support: true, en_dc_support: true,
{%- endif %} {%- endif %}
// LTE cells // LTE cells
cell_list: [ cell_list: [
{%- if do_lte %} {%- if do_lte %}
{%- for i, k in enumerate(cell_list) %} {%- for cell_ref, icell in icell_dict_lte|dictsort %}
{%- set cell = icell['_'] %}
{%- set ru_ref = J(jcell_ru_ref(icell, icell_dict)) %}
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
// {{ B(cell_ref) }} ({{ B(ru_ref) }})
{ {
rf_port: {{ i }}, rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }}, n_antenna_dl: {{ ru.n_antenna_dl }},
n_antenna_ul: {{ ru.n_antenna_ul }}, n_antenna_ul: {{ ru.n_antenna_ul }},
cell_id: {{ cell_list[k].get('cell_id', slapparameter_dict.get('cell_id', '0x0' + i|string)) }}, cell_id: {{ cell.cell_id }},
tac: {{ cell_list[k].get('tac', slapparameter_dict.get('tac', '0x0001')) }}, tac: {{ cell.tac }},
n_id_cell: {{ cell_list[k].get('pci', slapparameter_dict.get('pci', i)) }}, n_id_cell: {{ cell.pci }},
root_sequence_index: {{ cell_list[k].get('root_sequence_index', slapparameter_dict.get('root_sequence_index', 204 + i)) }}, dl_earfcn: {{ cell.dl_earfcn }},
dl_earfcn: {{ cell_list[k].get('dl_earfcn', slapparameter_dict.get('dl_earfcn', earfcn)) }}, ul_earfcn: {{ cell.ul_earfcn }},
inactivity_timer: {{ slapparameter_dict.get('inactivity_timer', slap_configuration['configuration.default_lte_inactivity_timer']) }}, root_sequence_index: {{ cell.root_sequence_index }},
inactivity_timer: {{ cell.inactivity_timer }},
// Handover // Handover
{{- handover_config() }} {{- handover_config(cell_ref) }}
// Carrier Aggregation // Carrier Aggregation: LTE + LTE
{%- set scell_list = [] %}
{%- for j, l in enumerate(cell_list) %}
{%- if j != i %}
{%- do scell_list.append([j, l]) %}
{%- endif %}
{%- endfor %}
scell_list: [ scell_list: [
{%- for j, l in enumerate(scell_list) %} {%- for cell2_ref, icell2 in icell_dict_lte|dictsort %}
{%- if j == 0 -%} {%- set cell2 = icell2['_'] %}
{%- if cell2_ref != cell_ref %}
{ {
{%- else -%} cell_id: {{ cell2.cell_id }}, // + {{ B(cell2_ref) }}
, {
{%- endif %}
cell_id: {{ cell_list[l[1]].get('cell_id', '0x0' + l[0]|string) }},
cross_carrier_scheduling: false, cross_carrier_scheduling: false,
} },
{%- endfor %} {%- endif %}
{%- endfor %}
], ],
{%- if do_nr %}
// Dual Connectivity: LTE + NR
en_dc_scg_cell_list: [
{%- for cell2_ref, icell2 in icell_dict_nr|dictsort %}
{%- set cell2 = icell2['_'] %}
{%- if cell2_ref != cell_ref %}
{
cell_id: {{ cell2.cell_id }}, // + {{ B(cell2_ref) }}
},
{%- endif %}
{%- endfor %}
],
{%- endif %}
// tune LTE parameters for the cell // tune LTE parameters for the cell
{% if ors %} {% if ors %}
manual_ref_signal_power: true, manual_ref_signal_power: true,
{% endif %} {% endif %}
{%- set tdd = (rf_mode == 'tdd') %} {%- set tdd = (cell.rf_mode == 'tdd') %}
{%- if tdd %} {%- if tdd %}
uldl_config: {{ tdd_config }}, uldl_config: {{
{'[Configuration 2] 5ms 2UL 6DL (default)': 2,
'[Configuration 6] 5ms 5UL 3DL (maximum uplink)': 6}
[cell.tdd_ul_dl_config]
}},
sp_config: 7, sp_config: 7,
{%- endif %} {%- endif %}
...@@ -345,11 +320,11 @@ ...@@ -345,11 +320,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_list) == 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_list) >= 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 %}
...@@ -388,11 +363,11 @@ ...@@ -388,11 +363,11 @@
srs_hopping_bandwidth: 0, srs_hopping_bandwidth: 0,
}, },
drb_config: "{{ drb_file }}", drb_config: "{{ B('%s-drb.cfg' % cell_ref) }}",
sib_sched_list: [ sib_sched_list: [
{ {
filename: "{{ sib23_file }}", filename: "{{ B('%s-sib23.asn' % cell_ref) }}",
si_periodicity: 16, si_periodicity: 16,
}, },
], ],
...@@ -404,21 +379,13 @@ ...@@ -404,21 +379,13 @@
{%- if do_lte %} {%- if do_lte %}
cell_default: { cell_default: {
plmn_list: [ plmn_list: [
{%- if slapparameter_dict.get('plmn_list', '') %} {%- for _, plmn in slapparameter_dict.plmn_list |dictsort %}
{%- for i, k in enumerate(slapparameter_dict['plmn_list']) %}
{%- if i == 0 -%}
{ {
{%- else -%} plmn: "{{ plmn.plmn }}",
, { reserved: {{ plmn.get('reserved', false) |tojson }},
{%- endif %} attach_without_pdn: {{ plmn.get('attach_without_pdn', false) |tojson }},
plmn: "{{ slapparameter_dict['plmn_list'][k]['plmn'] }}", },
reserved: {{ str(slapparameter_dict['plmn_list'][k].get('reserved', false)).lower() }}, {%- endfor %}
attach_without_pdn: {{ str(slapparameter_dict['plmn_list'][k].get('attach_without_pdn', false)).lower() }},
}
{%- endfor -%}
{% else %}
"00101",
{% endif %}
], ],
cyclic_prefix: "normal", cyclic_prefix: "normal",
...@@ -506,35 +473,67 @@ ...@@ -506,35 +473,67 @@
{% if do_nr %} {% if do_nr %}
// NR cells // NR cells
nr_cell_list: [ nr_cell_list: [
{%- for cell_ref, icell in icell_dict_nr|dictsort %}
{%- set cell = icell['_'] %}
{%- set ru_ref = J(jcell_ru_ref(icell, icell_dict)) %}
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
// {{ B(cell_ref) }} ({{ B(ru_ref) }})
{ {
rf_port: 0, rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }}, n_antenna_dl: {{ ru.n_antenna_dl }},
n_antenna_ul: {{ ru.n_antenna_ul }}, n_antenna_ul: {{ ru.n_antenna_ul }},
cell_id: {{ slapparameter_dict.get('cell_id', '0x01') }}, cell_id: {{ cell.cell_id }},
n_id_cell: {{ slapparameter_dict.get('pci', 500) }}, n_id_cell: {{ cell.pci }},
band: {{ nr_band }}, band: {{ cell.nr_band }},
dl_nr_arfcn: {{ nr_arfcn }}, dl_nr_arfcn: {{ cell.dl_nr_arfcn }},
bandwidth: {{ slapparameter_dict.get('nr_bandwidth', slap_configuration['configuration.default_nr_bandwidth']) }}, ul_nr_arfcn: {{ cell.ul_nr_arfcn }},
bandwidth: {{ cell.bandwidth }},
subcarrier_spacing: 30, subcarrier_spacing: {{ cell.subcarrier_spacing }},
ssb_pos_bitmap: "{{ slapparameter_dict.get('ssb_pos_bitmap', slap_configuration['configuration.default_nr_ssb_pos_bitmap']) }}", ssb_nr_arfcn: {{ cell.ssb_nr_arfcn }},
ssb_pos_bitmap: "{{ cell.ssb_pos_bitmap }}",
inactivity_timer: {{ slapparameter_dict.get('inactivity_timer', slap_configuration['configuration.default_nr_inactivity_timer']) }}, root_sequence_index: {{ cell.root_sequence_index }},
inactivity_timer: {{ cell.inactivity_timer }},
// Handover // Handover
{{- handover_config() }} {{- handover_config(cell_ref) }}
// Carrier Aggregation: NR + NR
scell_list: [
{%- for cell2_ref, icell2 in icell_dict_nr|dictsort %}
{%- set cell2 = icell2['_'] %}
{%- if cell2_ref != cell_ref %}
{
cell_id: {{ cell2.cell_id }}, // + {{ B(cell2_ref) }}
},
{%- endif %}
{%- endfor %}
],
{#- NOTE: NR + LTE Dual Connectivity is setup via EN-DC only - via en_dc_scg_cell_list.
nr_dc_scg_cell_list sets up NR+NR Dual Connectivity #}
// tune NR parameters for the cell // tune NR parameters for the cell
{%- if ors %} {%- if ors %}
manual_ref_signal_power: true, manual_ref_signal_power: true,
{%- if ors['one-watt'] %} {%- if ors['one-watt'] %}
ss_pbch_block_power: {{ (tx_gain | int) - 54 }}, ss_pbch_block_power: {{ ru.tx_gain - 54 }},
{%- else %} {%- else %}
ss_pbch_block_power: {{ (tx_gain | int) - 35 }}, ss_pbch_block_power: {{ ru.tx_gain - 35 }},
{%- endif -%} {%- endif -%}
{%- endif %} {%- endif %}
{%- set tdd = (cell.rf_mode == 'tdd') %}
{%- set tdd_config =
{'5ms 2UL 7DL 4/6 (default)': 1,
'2.5ms 1UL 3DL 2/10': 2,
'5ms 8UL 1DL 2/10 (maximum uplink)': 3}
[cell.tdd_ul_dl_config]
if tdd else None %}
{% if tdd_config == 1 %} {% if tdd_config == 1 %}
tdd_ul_dl_config: { tdd_ul_dl_config: {
pattern1: { pattern1: {
...@@ -568,51 +567,50 @@ ...@@ -568,51 +567,50 @@
{% endif %} {% endif %}
prach: { prach: {
{% if ru.ru_type == "m2ru" %} {%- if ru.ru_type == "sunwave" %}
msg1_frequency_start: 0, msg1_frequency_start: 0,
{% endif %} {%- endif %}
ra_response_window: {{ 20 if tdd else 10 }},
}, },
pdcch: { pdcch: {
{% if ru.ru_type == "m2ru" %} {%- if ru.ru_type == "sunwave" %}
n_rb_coreset0: 48, n_rb_coreset0: 48,
n_symb_coreset0: 1, n_symb_coreset0: 1,
dedicated_coreset: { dedicated_coreset: {
{% if ru.ru_type == "m2ru" %}
duration: 1, duration: 1,
{% endif %}
}, },
{% endif %} {%- endif %}
{% if tdd_config == 3 %} {%- if tdd_config == 3 %}
uss: { uss: {
n_candidates: [ 0, 8, 1, 0, 0 ], n_candidates: [ 0, 8, 1, 0, 0 ],
dci_0_1_and_1_1: true, dci_0_1_and_1_1: true,
}, },
{% else %} {%- else %}
uss: { uss: {
n_candidates: [ 0, 2, 1, 0, 0 ], n_candidates: [ 0, 2, 1, 0, 0 ],
dci_0_1_and_1_1: true, dci_0_1_and_1_1: true,
}, },
{% endif %} {%- endif %}
}, },
pdsch: { pdsch: {
{% if ru.ru_type == "m2ru" %} {%- if ru.ru_type == "sunwave" %}
k0: 0, k0: 0,
k1: [ 8, 7, 7, 6, 5, 4, 12, 11 ], k1: [ 8, 7, 7, 6, 5, 4, 12, 11 ],
{% elif tdd_config == 3 %} {%- elif tdd_config == 3 %}
k1: [4, 11], k1: [4, 11],
{% endif %} {%- endif %}
}, },
pusch: { pusch: {
{% if ru.ru_type == "m2ru" %} {%- if ru.ru_type == "sunwave" %}
k2: 4, k2: 4,
msg3_k2: 7, msg3_k2: 7,
{% elif tdd_config == 3 %} {%- elif tdd_config == 3 %}
k2: [11, 12, 4, 5, 6, 7, 7, 8], k2: [11, 12, 4, 5, 6, 7, 7, 8],
msg3_k2: 7, msg3_k2: 7,
{% endif %} {%- endif %}
}, },
csi_rs: { csi_rs: {
...@@ -639,10 +637,10 @@ ...@@ -639,10 +637,10 @@
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 %}
{ {
csi_rs_id: 1, csi_rs_id: 1,
n_ports: 1, n_ports: 1,
...@@ -707,31 +705,31 @@ ...@@ -707,31 +705,31 @@
offset: 12, offset: 12,
qcl_info_periodic_csi_rs: 0, qcl_info_periodic_csi_rs: 0,
}, },
{% endif %} {%- endif %}
], ],
nzp_csi_rs_resource_set: [ nzp_csi_rs_resource_set: [
{}, {},
{% if tdd_config != 3 %} {%- if tdd_config != 3 %}
{ {
csi_rs_set_id: 1, csi_rs_set_id: 1,
nzp_csi_rs_resources: [ 1, 2, 3, 4 ], nzp_csi_rs_resources: [ 1, 2, 3, 4 ],
repetition: false, repetition: false,
trs_info: true, trs_info: true,
}, },
{% endif %} {%- endif %}
], ],
csi_resource_config: [ csi_resource_config: [
{}, {},
{}, {},
{% if tdd_config != 3 %} {%- if tdd_config != 3 %}
{ {
csi_rsc_config_id: 2, csi_rsc_config_id: 2,
nzp_csi_rs_resource_set_list: [ 1 ], nzp_csi_rs_resource_set_list: [ 1 ],
resource_type: "periodic", resource_type: "periodic",
}, },
{% endif %} {%- endif %}
], ],
csi_report_config: [ csi_report_config: [
...@@ -756,81 +754,43 @@ ...@@ -756,81 +754,43 @@
], ],
}, },
drb_config: "{{ drb_file }}", drb_config: "{{ B('%s-drb.cfg' % cell_ref) }}",
}, },
{%- endfor %}
], ],
nr_cell_default: { nr_cell_default: {
ssb_period: 20, ssb_period: 20,
plmn_list: [ plmn_list: [
{%- if slapparameter_dict.get('plmn_list', '') %} {%- for _, plmn in slapparameter_dict.plmn_list_5g |dictsort %}
{%- for i, k in enumerate(slapparameter_dict['plmn_list']) %}
{%- if i == 0 -%}
{ {
{%- else -%} plmn: "{{ plmn.plmn }}",
, { tac: {{ plmn.tac }},
{%- if plmn.get('ranac') %}
ranac: {{ plmn.ranac }},
{%- endif %} {%- endif %}
plmn: "{{ slapparameter_dict['plmn_list'][k]['plmn'] }}", reserved: {{ plmn.get('reserved', false) |tojson }},
tac: {{ slapparameter_dict['plmn_list'][k].get('tac', 100) }},
{%- if slapparameter_dict['plmn_list'][k].get('ranac', '') %}
ranac: {{ slapparameter_dict['plmn_list'][k]['ranac'] }},
{%- endif %}
reserved: {{ str(slapparameter_dict['plmn_list'][k].get('reserved', false)).lower() }},
nssai: [ nssai: [
{%- if slapparameter_dict.get('nssai', '') %} {%- for _, nssai in slapparameter_dict.nssai |dictsort %}
{%- for j, k in enumerate(slapparameter_dict['nssai']) %}
{%- if j == 0 %}
{ {
{%- else -%} sst: {{ nssai.sst }},
, { {%- if nssai.get('sd') %}
sd: {{ nssai.sd }},
{%- endif %} {%- endif %}
sst: {{ slapparameter_dict['nssai'][k]['sst'] }},
{%- if slapparameter_dict['nssai'][k].get('sd', '') %}
sd: {{ slapparameter_dict['nssai'][k]['sd'] }},
{%- endif %}
}
{%- endfor -%}
{% else %}
{
sst: 1,
},
{% endif %}
],
}
{%- endfor -%}
{% else %}
{
plmn: "00101",
tac: 100,
reserved: false,
nssai: [
{%- if slapparameter_dict.get('nssai', '') %}
{%- for j, k in enumerate(slapparameter_dict['nssai']) %}
{%- if j == 0 %}
{
{%- else -%}
, {
{%- endif %}
sst: {{ slapparameter_dict['nssai'][k]['sst'] }},
{%- if slapparameter_dict['nssai'][k].get('sd', '') %}
sd: {{ slapparameter_dict['nssai'][k]['sd'] }},
{%- endif %}
}
{%- endfor -%}
{% else %}
{
sst: 1,
}, },
{% endif %} {%- endfor %}
], ],
}, },
{%- endif %} {%- endfor %}
], ],
si_window_length: 40, si_window_length: 40,
cell_barred: false, cell_barred: false,
intra_freq_reselection: true, intra_freq_reselection: true,
q_rx_lev_min: -70, q_rx_lev_min: -70,
q_qual_min: -20, q_qual_min: -20,
root_sequence_index: 1,
sr_period: 40, sr_period: 40,
dmrs_type_a_pos: 2, dmrs_type_a_pos: 2,
prach: { prach: {
...@@ -842,7 +802,6 @@ ...@@ -842,7 +802,6 @@
preamble_received_target_power: -110, preamble_received_target_power: -110,
preamble_trans_max: 7, preamble_trans_max: 7,
power_ramping_step: 4, power_ramping_step: 4,
ra_response_window: 20,
restricted_set_config: "unrestricted_set", restricted_set_config: "unrestricted_set",
ra_contention_resolution_timer: 64, ra_contention_resolution_timer: 64,
ssb_per_prach_occasion: 1, ssb_per_prach_occasion: 1,
......
{%- set B = xbuildout.encode -%}
/* SIB2/SIB3 for {{ cell.cell_type | upper }} cell {{ B(cell_ref) }} @ {{ B(ru_ref) }}. */
{ {
message c1: systemInformation: { message c1: systemInformation: {
criticalExtensions systemInformation-r8: { criticalExtensions systemInformation-r8: {
...@@ -38,9 +40,9 @@ ...@@ -38,9 +40,9 @@
pdsch-ConfigCommon { pdsch-ConfigCommon {
{% if ors %} {% if ors %}
{%- if ors['one-watt'] %} {%- if ors['one-watt'] %}
referenceSignalPower {{ (tx_gain | int) - 54 }}, /* patched by eNB */ referenceSignalPower {{ (ru.tx_gain | int) - 54 }}, /* patched by eNB */
{%- else %} {%- else %}
referenceSignalPower {{ (tx_gain | int) - 35 }}, /* patched by eNB */ referenceSignalPower {{ (ru.tx_gain | int) - 35 }}, /* patched by eNB */
{%- endif %} {%- endif %}
{% else %} {% else %}
referenceSignalPower -8, /* patched by eNB */ referenceSignalPower -8, /* patched by eNB */
......
{#- do_lte/do_nr indicate whether we have LTE or NR UE/cells #} {%- import 'slaplte.jinja2' as slaplte with context %}
{%- do assert(do_lte or do_nr) %} {%- set B = slaplte.B %}
{%- do assert(not (do_lte and do_nr)) %} {%- set J = slaplte.J %}
{%- set jcell_ru_ref = slaplte.jcell_ru_ref %}
{#- for standalone testing via slapos-render-config.py
NOTE: keep in sync with instance-ue.jinja2.cfg and ru/libinstance.jinja2.cfg #}
{%- if _standalone is defined %}
{%- set iru_dict = {} %}
{%- set icell_dict = {} %}
{%- set iue_dict = {} %}
{%- do slaplte.load_iru_and_icell(iru_dict, icell_dict, icell_kind='ue') %}
{%- do slaplte.load_iue(iue_dict) %}
{%- do slaplte.check_loaded_everything() %}
{%- endif %}
{#- start of the config -#}
{ {
log_options: "all.level=error,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1,phy.level=info,file.rotate=1G,file.path=/dev/null", log_options: "all.level=error,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1,phy.level=info,file.rotate=1G,file.path=/dev/null",
log_filename: "{{ directory['log'] }}/ue.log", log_filename: "{{ directory['log'] }}/ue.log",
...@@ -9,72 +23,98 @@ ...@@ -9,72 +23,98 @@
rue_bind_addr: "{{ pub_info['rue_bind_addr'] }}", rue_bind_addr: "{{ pub_info['rue_bind_addr'] }}",
com_addr: "{{ pub_info['com_addr'] }}", com_addr: "{{ pub_info['com_addr'] }}",
rf_driver: { {# instantiate radio units #}
name: "sdr", {{ slaplte.ru_config(iru_dict, slapparameter_dict) }}
args: "dev0=/dev/sdr0",
rx_antenna:"tx_rx",
}, cell_groups: [{
tx_gain: {{ slapparameter_dict.get('tx_gain', 60) }}, // LTE cells
rx_gain: {{ slapparameter_dict.get('rx_gain', 40) }}, group_type: "lte",
cell_groups: [
{%- if do_lte %}
{
// LTE cell
multi_ue: true, multi_ue: true,
cells: [ cells: [
{%- for cell_ref, icell in icell_dict|dictsort %}
{%- set cell = icell['_'] %}
{%- if cell.cell_type == 'lte' %}
{%- set ru_ref = J(jcell_ru_ref(icell)) %}
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
// {{ B(cell_ref) }}
{ {
bandwidth: {{ slapparameter_dict.get('bandwidth', slap_configuration['configuration.default_lte_bandwidth']) .removesuffix(' MHz') }}, rf_port: {{ ru._rf_port }},
dl_earfcn: {{ slapparameter_dict.get('dl_earfcn', 0) }}, n_antenna_dl: {{ ru.n_antenna_dl }},
n_antenna_dl: {{ slapparameter_dict.get('n_antenna_dl', slap_configuration['configuration.default_n_antenna_dl']) }}, n_antenna_ul: {{ ru.n_antenna_ul }},
n_antenna_ul: {{ slapparameter_dict.get('n_antenna_ul', slap_configuration['configuration.default_n_antenna_ul']) }},
dl_earfcn: {{ cell.dl_earfcn }},
ul_earfcn: {{ cell.ul_earfcn }},
bandwidth: {{ cell.bandwidth }},
global_timing_advance: -1, global_timing_advance: -1,
} },
{%- endif %}
{%- endfor %}
], ],
pdcch_decode_opt: false, pdcch_decode_opt: false,
pdcch_decode_opt_threshold: 0.1, pdcch_decode_opt_threshold: 0.1,
},
{%- endif %} }, {
{%- if do_nr %} // NR cells
{
// NR cell
group_type: "nr", group_type: "nr",
multi_ue: false, multi_ue: true,
cells: [{
rf_port: 0, cells: [
bandwidth: {{ slapparameter_dict.get('bandwidth', slap_configuration['configuration.default_nr_bandwidth']) }}, {%- for cell_ref, icell in icell_dict|dictsort %}
band: {{ slapparameter_dict.get('nr_band', 0) }}, {%- set cell = icell['_'] %}
dl_nr_arfcn: {{ slapparameter_dict.get('dl_nr_arfcn', 0) }}, {%- if cell.cell_type == 'nr' %}
ssb_nr_arfcn: {{ slapparameter_dict.get('ssb_nr_arfcn', 0) }}, {%- set ru_ref = J(jcell_ru_ref(icell)) %}
subcarrier_spacing: 30, {%- set iru = iru_dict[ru_ref] %}
n_antenna_dl: {{ slapparameter_dict.get('n_antenna_dl', slap_configuration['configuration.default_n_antenna_dl']) }}, {%- set ru = iru['_'] %}
n_antenna_ul: {{ slapparameter_dict.get('n_antenna_ul', slap_configuration['configuration.default_n_antenna_ul']) }}, // {{ B(cell_ref) }}
} {
], rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }},
n_antenna_ul: {{ ru.n_antenna_ul }},
band: {{ cell.nr_band }},
dl_nr_arfcn: {{ cell.dl_nr_arfcn }},
ul_nr_arfcn: {{ cell.ul_nr_arfcn }},
ssb_nr_arfcn: {{ cell.ssb_nr_arfcn }},
bandwidth: {{ cell.bandwidth }},
subcarrier_spacing: {{ cell.subcarrier_spacing }},
}, },
{%- endif %} {%- endif %}
], {%- endfor %}
]
}],
ue_list: [ ue_list: [
{%- for ue_ref, iue in iue_dict|dictsort %}
{%- set ue = iue['_'] %}
// {{ B(ue_ref) }}
{ {
sim_algo: "{{ slapparameter_dict.get('sim_algo', 'milenage') }}", sim_algo: "{{ ue.sim_algo }}",
opc: "{{ slapparameter_dict.get('opc', '') }}", opc: "{{ ue.opc }}",
amf: {{ slapparameter_dict.get('amf', '0x9001') }}, amf: {{ ue.amf }},
sqn: "{{ slapparameter_dict.get('sqn', '000000000000') }}", sqn: "{{ ue.sqn }}",
impu: "{{ slapparameter_dict.get('impu', '') }}", impu: "{{ ue.impu }}",
impi: "{{ slapparameter_dict.get('impi', '') }}", impi: "{{ ue.impi }}",
{%- if do_lte %} imsi: "{{ ue.imsi }}",
imsi: "{{ slapparameter_dict.get('imsi', slap_configuration['configuration.default_lte_imsi']) }}", K: "{{ ue.k }}",
K: "{{ slapparameter_dict.get('k', slap_configuration['configuration.default_lte_k']) }}", rue_addr: "{{ ue.rue_addr }}",
ue_category: 12, {%- if ue.ue_type == 'lte' %}
{%- endif %} as_release: 13,
{%- if do_nr %} ue_category: 13,
imsi: "{{ slapparameter_dict.get('imsi', slap_configuration['configuration.default_nr_imsi']) }}", {%- elif ue.ue_type == 'nr' %}
K: "{{ slapparameter_dict.get('k', slap_configuration['configuration.default_nr_k']) }}",
as_release: 15, as_release: 15,
ue_category: "nr", ue_category: "nr",
{%- else %}
{%- do bug('unreachable') %}
{%- endif %} {%- endif %}
rue_addr: "{{ slapparameter_dict.get('rue_addr', '') }}",
tun_setup_script: "ue-ifup", tun_setup_script: "ue-ifup",
apn: "internet", apn: "internet",
} },
{%- endfor %}
], ],
} }
{
"$schema": "http://json-schema.org/draft-04/schema",
"description": "Values returned by Core Network instantiation (stub)",
"type": "object",
"properties": {}
}
...@@ -183,7 +183,7 @@ context = ...@@ -183,7 +183,7 @@ context =
section directory directory section directory directory
section slap_configuration slap-configuration section slap_configuration slap-configuration
key slapparameter_dict slap-configuration:configuration key slapparameter_dict slap-configuration:configuration
key gtp_addr_v6 slap-configuration:ipv6-random raw gtp_addr_v6 {{ my_ipv6 }}
raw gtp_addr_v4 {{ lan_ipv4 }} raw gtp_addr_v4 {{ lan_ipv4 }}
import netaddr netaddr import netaddr netaddr
key ifup_empty mme-ifup-empty:wrapper-path key ifup_empty mme-ifup-empty:wrapper-path
...@@ -245,7 +245,7 @@ password = {{ slapparameter_dict['monitor-password'] | string }} ...@@ -245,7 +245,7 @@ password = {{ slapparameter_dict['monitor-password'] | string }}
[publish-connection-information] [publish-connection-information]
<= monitor-publish <= monitor-publish
recipe = slapos.cookbook:publish.serialised recipe = slapos.cookbook:publish.serialised
core-network-ipv6 = ${slap-configuration:ipv6-random} core-network-ipv6 = {{ my_ipv6 }}
core-network-ipv4 = {{ lan_ipv4 }} core-network-ipv4 = {{ lan_ipv4 }}
amarisoft-version = {{ lte_version }} amarisoft-version = {{ lte_version }}
license-expiration = {{ lte_expiration }} license-expiration = {{ lte_expiration }}
......
...@@ -3,87 +3,16 @@ ...@@ -3,87 +3,16 @@
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {
"bandwidth": { "user-authorized-key": {
"title": "Bandwidth", "title": "User Authorized Key",
"description": "Downlink Bandwidth", "description": "SSH public key in order to connect to the SSH server of this instance.",
"type": "string", "textarea": true,
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "1, 2, 4 or 8. Number of DL antennas.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "1, 2, 4 or 8. Number of UL antennas.",
"type": "number",
"default": 2
},
"sdr_number": {
"title": "SDR Number",
"description": "SDR Number",
"type": "number",
"default": 0
},
"cpri_port": {
"title": "CPRI Port Number",
"description": "CPRI Port Number",
"type": "number",
"default": 0
},
"cell_list": {
"title": "Cell List",
"description": "Cell List",
"patternProperties": {
".*": {
"properties": {
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell IDs",
"type": "number"
},
"cell_id": {
"title": "Cell ID",
"description": "Cell IDs",
"type": "string" "type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
}, },
"enb_id": { "enb_id": {
"title": "eNB ID", "title": "eNB ID",
"description": "eNB ID", "description": "eNB ID. (must be set if there are LTE cells)",
"type": "string", "type": "string"
"default": "0x1A2D0"
}, },
"gtp_addr": { "gtp_addr": {
"title": "GTP Address", "title": "GTP Address",
...@@ -93,7 +22,7 @@ ...@@ -93,7 +22,7 @@
}, },
"mme_list": { "mme_list": {
"title": "MME list", "title": "MME list",
"description": "Optionnal. List of MME to which the gNodeB is connected", "description": "List of MME to which the eNodeB is connected. (must be set if there are LTE cells)",
"patternProperties": { "patternProperties": {
".*": { ".*": {
"properties": { "properties": {
...@@ -106,17 +35,15 @@ ...@@ -106,17 +35,15 @@
"type": "object" "type": "object"
} }
}, },
"type": "object", "type": "object"
"default": {}
}, },
"plmn_list": { "plmn_list": {
"title": "PLMN list", "title": "PLMN list (4G)",
"description": "List of PLMNs broadcasted by the eNodeB, at most 6 (default: 00101)", "description": "List of PLMNs broadcasted by the eNodeB, at most 6. (must be set if there are LTE cells)",
"patternProperties": { "patternProperties": {
".*": { ".*": {
"properties": { "properties": {
"plmn": { "plmn": {
"default": "00101",
"title": "Public Land Mobile Network", "title": "Public Land Mobile Network",
"description": "Public Land Mobile Network", "description": "Public Land Mobile Network",
"type": "string" "type": "string"
...@@ -137,64 +64,84 @@ ...@@ -137,64 +64,84 @@
"type": "object" "type": "object"
} }
}, },
"type": "object", "type": "object"
"default": {}
}, },
"lte_handover_a3_offset": { "gnb_id": {
"title": "A3 offset for LTE handover", "title": "gNB ID",
"description": "RSRP gain offset between gNBs which will trigger handover", "description": "gNB ID. (must be set if there are NR cells)",
"type": "number", "type": "string"
"default": 6
}, },
"lte_handover_time_to_trigger": { "gnb_id_bits": {
"title": "Time to Trigger for LTE handover", "title": "gNB ID bits",
"description": "Time to triger after which LTE handover will be triggered if A3 offset is reached", "description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number", "type": "number",
"enum": [ "default": 28
0, },
40, "amf_list": {
64, "title": "AMF list",
80, "description": "List of AMF to which the gNodeB is connected. (must be set if there are NR cells)",
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 480
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": { "patternProperties": {
".*": { ".*": {
"properties": { "properties": {
"dl_earfcn": { "amf_addr": {
"title": "DL EARFCN", "title": "AMF Address",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the neighbour cell", "description": "IP address (and optional port) of NGAP SCTP connection to the AMF. The default port is 38412.",
"type": "number" "type": "string"
}
}, },
"pci": { "type": "object"
"title": "Physical Cell ID", }
"description": "Physical Cell ID of the neighbour cell", },
"type": "number" "type": "object"
}, },
"cell_id": { "plmn_list_5g": {
"title": "Cell ID", "title": "PLMN list (5G)",
"description": "Concatenation of enb_id and cell_id of the neighbour cell", "description": "List of PLMNs broadcasted by the gNodeB, at most 12. (must be set if there are NR cells)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string" "type": "string"
}, },
"tac": { "tac": {
"title": "Tracking Area Code", "$ref": "cell/nr/input-schema.json#/$defs/tac"
"description": "Integer (range 0 to 16777215)", },
"ranac": {
"title": "Optional integer (range 0 to 255)",
"description": "RAN Area Code",
"type": "number" "type": "number"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object"
},
"nssai": {
"title": "AMF slices configuration",
"description": "AMF slices configuration.",
"patternProperties": {
".*": {
"properties": {
"sst": {
"default": 1,
"title": "Slice Service Type",
"description": "Integer (range 1 to 255).",
"type": "number"
},
"sd": {
"default": "0x000032",
"title": "Slice Differentiator",
"description": "Optional integer (range 0 to 0xFFFFFE)",
"type": "string"
} }
}, },
"type": "object" "type": "object"
...@@ -208,12 +155,6 @@ ...@@ -208,12 +155,6 @@
"description": "Activates websocket for remote control and sets password", "description": "Activates websocket for remote control and sets password",
"type": "string" "type": "string"
}, },
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"log_phy_debug": { "log_phy_debug": {
"title": "Physical layer log debug", "title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs", "description": "Enable debug mode for physical layer logs",
...@@ -226,12 +167,6 @@ ...@@ -226,12 +167,6 @@
"description": "True if GPS should be used for synchronisation", "description": "True if GPS should be used for synchronisation",
"type": "boolean" "type": "boolean"
}, },
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": { "use_ipv4": {
"default": false, "default": false,
"title": "Use IPv4", "title": "Use IPv4",
...@@ -239,14 +174,14 @@ ...@@ -239,14 +174,14 @@
"type": "boolean" "type": "boolean"
}, },
"enb_stats_fetch_period": { "enb_stats_fetch_period": {
"title": "eNB statistics fetch period (seconds)", "title": "eNB/gNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get eNB statistics", "description": "Describes how often a call to Amarisoft remote API is made to get eNB/gNB statistics",
"type": "number", "type": "number",
"default": 60 "default": 60
}, },
"enb_drb_stats_enabled": { "enb_drb_stats_enabled": {
"title": "Enable eNB drb statistics", "title": "Enable eNB/gNB drb statistics",
"description": "Enable eNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI", "description": "Enable eNB/gNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean", "type": "boolean",
"default": true "default": true
}, },
......
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "{{ default_lte_bandwidth }}"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
{%- if bbu == 'ors' %}
"description": "1 or 2. Number of DL antennas.",
{%- else %}
"description": "1, 2, 4 or 8. Number of DL antennas.",
{%- endif %}
"type": "number",
"default": {{ default_n_antenna_dl }}
},
"n_antenna_ul": {
"title": "Number of UL antennas",
{%- if bbu == 'ors' %}
"description": "1 or 2. Number of UL antennas.",
{%- else %}
"description": "1, 2, 4 or 8. Number of UL antennas.",
{%- endif %}
"type": "number",
"default": {{ default_n_antenna_ul }}
},
{%- if rf_mode == 'tdd' %}
"tdd_ul_dl_config": {
"title": "TDD",
"description": "TDD",
"type": "string",
"enum": [
"[Configuration 2] 5ms 2UL 6DL (default)",
"[Configuration 6] 5ms 5UL 3DL (maximum uplink)"
],
"default": "5ms 2UL 7DL 4/6 (default)"
},
{%- endif %}
{%- if bbu != 'ors' %}
"sdr_number": {
"title": "SDR Number",
"description": "SDR Number",
"type": "number",
"default": 0
},
"cpri_port": {
"title": "CPRI Port Number",
"description": "CPRI Port Number",
"type": "number",
"default": 0
},
{%- endif %}
{%- if trx == 'cpri' %}
"cpri_mult": {
"title": "CPRI Mult",
"description": "Select the CPRI line bit rate in terms of multiple of option 1 (614.4 Mbps). E.g set 4 for option 3, 8 for option 5 and 16 for option 7.",
"type": "number",
"default": 16,
"enum": [
4,
5,
8,
16
]
},
{%- endif %}
{%- if bbu == 'ors' %}
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID",
"type": "number",
"default": 1
},
"cell_id": {
"title": "Cell ID",
"description": "Cell ID",
"type": "string",
"default": "0x01"
},
"tac": {
"title": "Tracking Area Code",
"description": "Tracking Area Code in hexadecimal representation (range 0x0000 to 0xffff)",
"default": "0x0001",
"type": "string"
},
"root_sequence_index": {
"title": "Root Sequence Index",
"description": "Range: 0 to 837. Set the PRACH root sequence index (SIB2.rootSequenceIndex field). It must be different for each neighbour cell operating on the same frequency and sharing the same PRACH configuration.",
"type": "number",
"default": 204
},
{%- else %}
"cell_list": {
"title": "Cell List",
"description": "Cell List",
"patternProperties": {
".*": {
"properties": {
{%- if trx == 'cpri' %}
"cpri_rx_delay": {
"title": "CPRI RX Delay",
"description": "Delays between TX and RX position in CPRI frame. This should be set to the value of (T2a + T3a - Toffset) provided by the RRH specification.",
"type": "number",
"default": 25.11
},
"cpri_tx_delay": {
"title": "CPRI TX Delay",
"description": "Advances Start of Frame relative to PPS to compensate for delays in transmit line and RRH. This should be set to T12 + T2a.",
"type": "number",
"default": 14.71
},
"cpri_tx_dbm": {
"title": "CPRI TX dBm",
"description": "Optional floating points value in dBm (default 0). Needed by ENB/GNB to have a notion of actual output power. Computed from maximum power output of the RRH for a 0dBFS input signal (full scale). ",
"type": "number",
"default": 63
},
"cpri_port_number": {
"title": "CPRI Port Number",
"description": "CPRI Port Number",
"type": "number",
"default": 0
},
"ru_mac_addr": {
"title": "RU MAC address",
"description": "RU MAC address used for NETCONF",
"type": "string"
},
{%- endif %}
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell IDs",
"type": "number"
},
"cell_id": {
"title": "Cell ID",
"description": "Cell IDs",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
{%- endif %}
{%- if trx == 'sdr' %}
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
{%- endif %}
{%- if ru == 'lopcomm' %}
"txa0cc00_active": {
"title": "Lopcomm ORAN TX array carriers (TXA0CC00)",
"description": "Activate or inactivate Lopcomm ORAN TX array carriers (TXA0CC00)",
"type": "string",
"default": "INACTIVE",
"enum": [
"ACTIVE",
"INACTIVE"
]
},
"rxa0cc00_active": {
"title": "Lopcomm ORAN RX array carriers (RXA0CC00)",
"description": "Activate or inactivate Lopcomm ORAN RX array carriers (RXA0CC00)",
"type": "string",
"default": "INACTIVE",
"enum": [
"ACTIVE",
"INACTIVE"
]
},
"txa0cc00_center_frequency": {
"title": "Lopcomm ORAN DL Center Frequency in MHz (TXA0CC00)",
"description": "Lopcomm ORAN Center Frequency in MHz (TXA0CC00)",
"type": "number",
"default": 2140
},
"rxa0cc00_center_frequency_earfcn": {
"title": "Lopcomm ORAN UL Center Frequency EARFCN (RXA0CC00)",
"description": "Lopcomm ORAN Center Frequency EARFCN (RXA0CC00)",
"type": "number",
"default": 18300
},
"rxa0cc00_center_frequency": {
"title": "Lopcomm ORAN UL Center Frequency in MHz (RXA0CC00)",
"description": "Lopcomm ORAN Center Frequency in MHz (RXA0CC00)",
"type": "number",
"default": 1950
},
"txa0cc00_gain": {
"title": "ORAN Gain",
"description": "Lopcomm ORAN Gain (TXA0CC00)",
"type": "number",
"default": -20
},
"user-authorized-key": {
"title": "User Authorized Key",
"description": "SSH public key in order to connect to the SSH server of this instance.",
"textarea": true,
"type": "string"
},
"cron_schedule": {
"title": "Cron schedule for RRH reset",
"description": "Refer https://crontab.guru/ to make a reset schedule for RRH, for example, '0 1 * * *' means the RRH will reset every day at 1 am",
"type": "string"
},
{%- endif %}
"enb_id": {
"title": "eNB ID",
"description": "eNB ID",
"type": "string",
"default": "0x1A2D0"
},
"gtp_addr": {
"title": "GTP Address",
"description": "String. Set the IP address (and optional port) on which the GTP-U packets are received. The default port is 2152. It is normally the IP address of the network interface connected to the core network.",
"type": "string",
"default": "127.0.1.1"
},
"mme_list": {
"title": "MME list",
"description": "Optionnal. List of MME to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"mme_addr": {
"title": "MME Address",
"description": "IP address (and optional port) of S1AP SCTP connection to the MME. The default port is 36412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the eNodeB, at most 6 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"attach_without_pdn": {
"default": false,
"title": "Attach Without PDN",
"description": "Optional boolean. Indicates if PLMN supports attach without PDN connectivity.",
"type": "boolean"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"lte_handover_a3_offset": {
"title": "A3 offset for LTE handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"lte_handover_time_to_trigger": {
"title": "Time to Trigger for LTE handover",
"description": "Time to triger after which LTE handover will be triggered if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 480
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"cell_id": {
"title": "Cell ID",
"description": "Concatenation of enb_id and cell_id of the neighbour cell",
"type": "string"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": {{ default_lte_inactivity_timer }}
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"enb_stats_fetch_period": {
"title": "eNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get eNB statistics",
"type": "number",
"default": 60
},
"enb_drb_stats_enabled": {
"title": "Enable eNB drb statistics",
"description": "Enable eNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
{
"$schema": "http://json-schema.org/draft-04/schema",
"description": "Values returned by eNB/gNB instantiation (stub)",
"type": "object",
"properties": {}
}
{#- enb_mode indicates with which mode enb is instantiated with - enb | gnb #} # instance-enb implements eNB/gNB service.
{%- set enb_mode = slap_configuration['slap-software-type'] %}
{%- do assert(enb_mode in ('enb', 'gnb'), enb_mode) %} {#- defaults for global eNB/gNB parameters.
TODO automatically load enb defaults from JSON schema #}
{%- set enb_defaults = {
'com_ws_port': 9001,
'com_addr': '127.0.1.2',
'use_ipv4': False,
'gnb_id_bits': 28,
'nssai': {'1': {'sst': 1}},
} %}
{%- set gtp_addr_lo = '127.0.1.1' %}
{%- for k,v in enb_defaults|dictsort %}
{%- do slapparameter_dict.setdefault(k, v) %}
{%- endfor %}
{#- defaults for eNB radio parameters.
NOTE they are installed temporary and will go away after switch to generic multiRU. #}
{%- do RF.setdefault('tx_gain', slapparameter_dict.get('tx_gain', 0)) %}
{%- do RF.setdefault('rx_gain', slapparameter_dict.get('rx_gain', 0)) %}
{%- do RF.setdefault('dl_earfcn', slapparameter_dict.get('dl_earfcn', 0)) %}
{%- do RF.setdefault('dl_nr_arfcn', slapparameter_dict.get('dl_nr_arfcn', 0)) %}
{%- do RF.setdefault('nr_band', slapparameter_dict.get('nr_band', 0)) %}
[buildout] [buildout]
parts = parts =
...@@ -29,10 +34,23 @@ eggs-directory = {{ eggs_directory }} ...@@ -29,10 +34,23 @@ eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }} develop-eggs-directory = {{ develop_eggs_directory }}
offline = true offline = true
{%- set icell_kind='enb' %}
{%- 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 ipeer_dict = {} %}
{%- set ipeercell_dict = {} %}
{%- do slaplte.load_ipeer(ipeer_dict) %}
{%- do slaplte.load_ipeercell(ipeercell_dict) %}
{%- do slaplte.check_loaded_everything() %}
{{ rulib.buildout() }} {{ rulib.buildout() }}
[myslap]
# NOTE we don't query slapos.cookbook:slapconfiguration the second time because
# slapparameter_dict is potentially modified with defaults.
parameter_dict = {{ dumps(slapparameter_dict) }}
configuration = {{ dumps(slap_configuration) }}
[monitor-httpd-conf-parameter] [monitor-httpd-conf-parameter]
httpd-include-file = {{ buildout_directory }}/etc/httpd-include-file.conf httpd-include-file = {{ buildout_directory }}/etc/httpd-include-file.conf
...@@ -48,26 +66,6 @@ minimum = 8035 ...@@ -48,26 +66,6 @@ minimum = 8035
maximum = 8055 maximum = 8055
ip = ${monitor-instance-parameter:monitor-httpd-ipv6} ip = ${monitor-instance-parameter:monitor-httpd-ipv6}
[slap-configuration]
recipe = slapos.cookbook:slapconfiguration.serialised
computer = {{ slap_connection['computer-id'] }}
partition = {{ slap_connection['partition-id'] }}
url = {{ slap_connection['server-url'] }}
key = {{ slap_connection['key-file'] }}
cert = {{ slap_connection['cert-file'] }}
configuration.com_ws_port = 9001
configuration.com_addr = 127.0.1.2
configuration.mme_addr = 127.0.1.100
configuration.amf_addr = 127.0.1.100
configuration.gtp_addr = 127.0.1.1
configuration.default_lte_bandwidth = {{ default_lte_bandwidth }}
configuration.default_lte_inactivity_timer = {{ default_lte_inactivity_timer }}
configuration.default_nr_bandwidth = {{ default_nr_bandwidth }}
configuration.default_nr_inactivity_timer = {{ default_nr_inactivity_timer }}
configuration.default_nr_ssb_pos_bitmap = {{ default_nr_ssb_pos_bitmap }}
configuration.default_n_antenna_dl = {{ default_n_antenna_dl }}
configuration.default_n_antenna_ul = {{ default_n_antenna_ul }}
[directory] [directory]
recipe = slapos.cookbook:mkdirectory recipe = slapos.cookbook:mkdirectory
...@@ -134,7 +132,7 @@ drb_stats_logspec = ...@@ -134,7 +132,7 @@ drb_stats_logspec =
rotatespec = 100MB.9 rotatespec = 100MB.9
logspec = ${:stats_logspec} ${:drb_stats_logspec} logspec = ${:stats_logspec} ${:drb_stats_logspec}
{%- if slapparameter_dict.get("websocket_password", "") %} {%- if slapparameter_dict.get("websocket_password", "") %}
websock = ws://[${slap-configuration:ipv6-random}]:9001 websock = ws://[{{my_ipv6}}]:9001
{%- else %} {%- else %}
websock = ws://127.0.1.2:9001 websock = ws://127.0.1.2:9001
{%- endif %} {%- endif %}
...@@ -194,44 +192,15 @@ extra-context = ...@@ -194,44 +192,15 @@ extra-context =
context = context =
json ors false json ors false
section directory directory section directory directory
section slap_configuration slap-configuration key slap_configuration myslap:configuration
key slapparameter_dict slap-configuration:configuration key slapparameter_dict myslap:parameter_dict
key gtp_addr_v6 slap-configuration:ipv6-random raw gtp_addr_v6 {{ my_ipv6 }}
raw gtp_addr_v4 {{ lan_ipv4 }} raw gtp_addr_v4 {{ lan_ipv4 }}
raw tx_gain {{ RF.tx_gain }} raw gtp_addr_lo {{ gtp_addr_lo }}
raw rx_gain {{ RF.rx_gain }} import xbuildout xbuildout
raw earfcn {{ RF.dl_earfcn }}
raw nr_arfcn {{ RF.dl_nr_arfcn }}
raw nr_band {{ RF.nr_band }}
raw software_name {{ software_name }}
raw rf_mode {{ rf_mode }}
raw trx {{ trx }}
raw bbu {{ bbu }}
raw ru_type {{ ru }}
{%- if enb_mode == 'enb' %}
json do_lte true
json do_nr false
{%- elif enb_mode == 'gnb' %}
json do_lte false
json do_nr true
{%- endif %}
import netaddr netaddr import netaddr netaddr
${:extra-context} ${:extra-context}
[sib-config]
<= config-base
url = {{ sib23_template }}
output = ${directory:etc}/sib23.cfg
[drb-config]
<= config-base
{%- if enb_mode == 'enb' %}
url = {{ drb_lte_template }}
{%- elif enb_mode == 'gnb' %}
url = {{ drb_nr_template }}
{%- endif %}
output = ${directory:etc}/drb.cfg
[enb-config] [enb-config]
<= config-base <= config-base
{% if slapparameter_dict.get("enb_config_link", None) %} {% if slapparameter_dict.get("enb_config_link", None) %}
...@@ -240,32 +209,36 @@ url = ${enb-config-dl:target} ...@@ -240,32 +209,36 @@ url = ${enb-config-dl:target}
url = {{ enb_template }} url = {{ enb_template }}
{% endif %} {% endif %}
output = ${directory:etc}/enb.cfg output = ${directory:etc}/enb.cfg
extra-context =
import json_module json
json cell_list {{ rulib.cell_list | tojson }}
key sib23_file sib-config:output
key drb_file drb-config:output
import-list = import-list =
rawfile slaplte.jinja2 {{ slaplte_template }} rawfile slaplte.jinja2 {{ slaplte_template }}
extra-context =
import json_module json
key iru_dict :iru_dict
key icell_dict :icell_dict
key ipeer_dict :ipeer_dict
key ipeercell_dict :ipeercell_dict
iru_dict = {{ dumps(rulib.iru_dict) }}
icell_dict = {{ dumps(rulib.icell_dict) }}
ipeer_dict = {{ dumps(ipeer_dict) }}
ipeercell_dict = {{ dumps(ipeercell_dict) }}
[publish-connection-information] [publish-connection-information]
<= monitor-publish <= monitor-publish
recipe = slapos.cookbook:publish.serialised recipe = slapos.cookbook:publish.serialised
{%- if slapparameter_dict.get("websocket_password", "") %} {%- if slapparameter_dict.get("websocket_password", "") %}
websocket_url = ws://[${slap-configuration:ipv6-random}]:9001 websocket_url = ws://[{{my_ipv6}}]:9001
{%- endif %} {%- endif %}
enb-ipv6 = ${slap-configuration:ipv6-random} enb-ipv6 = {{ my_ipv6 }}
enb-ipv4 = {{ lan_ipv4 }} enb-ipv4 = {{ lan_ipv4 }}
{%- if enb_mode == 'enb' %}
current-earfcn = {{ RF.dl_earfcn }}
{%- elif enb_mode == 'gnb' %}
current-nr-arfcn = {{ RF.dl_nr_arfcn }}
current-nr-band = {{ RF.nr_band }}
{%- endif %}
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) %}
......
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"nr_bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "1, 2, 4 or 8. Number of DL antennas.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "1, 2, 4 or 8. Number of UL antennas.",
"type": "number",
"default": 2
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"ssb_pos_bitmap": {
"title": "SSB Position Bitmap",
"description": "SSB position bitmap in bits (4, 8 or 64 bits depending on the DL frequency).",
"type": "string",
"default": 10000000
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID",
"type": "number",
"default": 500
},
"cell_id": {
"title": "Cell ID",
"description": "Cell ID",
"type": "string",
"default": "0x01"
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"gnb_id": {
"title": "gNB ID",
"description": "gNB ID",
"type": "string",
"default": "0x12345"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number",
"default": 28
},
"amf_list": {
"title": "AMF list",
"description": "Optionnal. List of AMF to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"amf_addr": {
"title": "AMF Address",
"description": "IP address (and optional port) of NGAP SCTP connection to the AMF. The default port is 38412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the gNodeB, at most 12 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"tac": {
"default": 100,
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
},
"ranac": {
"title": "Optional integer (range 0 to 255)",
"description": "RAN Area Code",
"type": "number"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nssai": {
"title": "AMF slices configuration",
"description": "AMF slices configuration.",
"patternProperties": {
".*": {
"properties": {
"sst": {
"default": 1,
"title": "Slice Service Type",
"description": "Integer (range 1 to 255).",
"type": "number"
},
"sd": {
"default": "0x000032",
"title": "Slice Differentiator",
"description": "Optional integer (range 0 to 0xFFFFFE)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nr_handover_a3_offset": {
"title": "A3 offset for NR handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"nr_handover_time_to_trigger": {
"title": "Time to Trigger for NR handover",
"description": "Time to triger after which NR handover will be triggerd if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 100
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"nr_cell_id": {
"title": "NR Cell ID",
"description": "Concatenation of gnb_id and cell_id of the neighbour cell",
"type": "string"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"xn_peers": {
"title": "XN Peers",
"description": "XN Peers",
"patternProperties": {
".*": {
"properties": {
"xn_addr": {
"title": "XN Address",
"description": "XN Address of the neighbour cell (gNB Address)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"gnb_stats_fetch_period": {
"title": "gNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get gNB statistics",
"type": "number",
"default": 60
},
"gnb_drb_stats_enabled": {
"title": "Enable gNB drb statistics",
"description": "Enable gNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "1, 2, 4 or 8. Number of DL antennas.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "1, 2, 4 or 8. Number of UL antennas.",
"type": "number",
"default": 2
},
"sdr_number": {
"title": "SDR Number",
"description": "SDR Number",
"type": "number",
"default": 0
},
"cpri_port": {
"title": "CPRI Port Number",
"description": "CPRI Port Number",
"type": "number",
"default": 0
},
"cpri_mult": {
"title": "CPRI Mult",
"description": "Select the CPRI line bit rate in terms of multiple of option 1 (614.4 Mbps). E.g set 4 for option 3, 8 for option 5 and 16 for option 7.",
"type": "number",
"default": 16,
"enum": [
4,
5,
8,
16
]
},
"cell_list": {
"title": "Cell List",
"description": "Cell List",
"patternProperties": {
".*": {
"properties": {
"cpri_rx_delay": {
"title": "CPRI RX Delay",
"description": "Delays between TX and RX position in CPRI frame. This should be set to the value of (T2a + T3a - Toffset) provided by the RRH specification.",
"type": "number",
"default": 25.11
},
"cpri_tx_delay": {
"title": "CPRI TX Delay",
"description": "Advances Start of Frame relative to PPS to compensate for delays in transmit line and RRH. This should be set to T12 + T2a.",
"type": "number",
"default": 14.71
},
"cpri_tx_dbm": {
"title": "CPRI TX dBm",
"description": "Optional floating points value in dBm (default 0). Needed by ENB/GNB to have a notion of actual output power. Computed from maximum power output of the RRH for a 0dBFS input signal (full scale). ",
"type": "number",
"default": 63
},
"cpri_port_number": {
"title": "CPRI Port Number",
"description": "CPRI Port Number",
"type": "number",
"default": 0
},
"ru_mac_addr": {
"title": "RU MAC address",
"description": "RU MAC address used for NETCONF",
"type": "string"
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell IDs",
"type": "number"
},
"cell_id": {
"title": "Cell ID",
"description": "Cell IDs",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"txa0cc00_active": {
"title": "Lopcomm ORAN TX array carriers (TXA0CC00)",
"description": "Activate or inactivate Lopcomm ORAN TX array carriers (TXA0CC00)",
"type": "string",
"default": "INACTIVE",
"enum": [
"ACTIVE",
"INACTIVE"
]
},
"rxa0cc00_active": {
"title": "Lopcomm ORAN RX array carriers (RXA0CC00)",
"description": "Activate or inactivate Lopcomm ORAN RX array carriers (RXA0CC00)",
"type": "string",
"default": "INACTIVE",
"enum": [
"ACTIVE",
"INACTIVE"
]
},
"txa0cc00_center_frequency": {
"title": "Lopcomm ORAN DL Center Frequency in MHz (TXA0CC00)",
"description": "Lopcomm ORAN Center Frequency in MHz (TXA0CC00)",
"type": "number",
"default": 2140
},
"rxa0cc00_center_frequency_earfcn": {
"title": "Lopcomm ORAN UL Center Frequency EARFCN (RXA0CC00)",
"description": "Lopcomm ORAN Center Frequency EARFCN (RXA0CC00)",
"type": "number",
"default": 18300
},
"rxa0cc00_center_frequency": {
"title": "Lopcomm ORAN UL Center Frequency in MHz (RXA0CC00)",
"description": "Lopcomm ORAN Center Frequency in MHz (RXA0CC00)",
"type": "number",
"default": 1950
},
"txa0cc00_gain": {
"title": "ORAN Gain",
"description": "Lopcomm ORAN Gain (TXA0CC00)",
"type": "number",
"default": -20
},
"user-authorized-key": {
"title": "User Authorized Key",
"description": "SSH public key in order to connect to the SSH server of this instance.",
"textarea": true,
"type": "string"
},
"cron_schedule": {
"title": "Cron schedule for RRH reset",
"description": "Refer https://crontab.guru/ to make a reset schedule for RRH, for example, '0 1 * * *' means the RRH will reset every day at 1 am",
"type": "string"
},
"enb_id": {
"title": "eNB ID",
"description": "eNB ID",
"type": "string",
"default": "0x1A2D0"
},
"gtp_addr": {
"title": "GTP Address",
"description": "String. Set the IP address (and optional port) on which the GTP-U packets are received. The default port is 2152. It is normally the IP address of the network interface connected to the core network.",
"type": "string",
"default": "127.0.1.1"
},
"mme_list": {
"title": "MME list",
"description": "Optionnal. List of MME to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"mme_addr": {
"title": "MME Address",
"description": "IP address (and optional port) of S1AP SCTP connection to the MME. The default port is 36412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the eNodeB, at most 6 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"attach_without_pdn": {
"default": false,
"title": "Attach Without PDN",
"description": "Optional boolean. Indicates if PLMN supports attach without PDN connectivity.",
"type": "boolean"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"lte_handover_a3_offset": {
"title": "A3 offset for LTE handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"lte_handover_time_to_trigger": {
"title": "Time to Trigger for LTE handover",
"description": "Time to triger after which LTE handover will be triggered if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 480
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"cell_id": {
"title": "Cell ID",
"description": "Concatenation of enb_id and cell_id of the neighbour cell",
"type": "string"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"enb_stats_fetch_period": {
"title": "eNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get eNB statistics",
"type": "number",
"default": 60
},
"enb_drb_stats_enabled": {
"title": "Enable eNB drb statistics",
"description": "Enable eNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"nr_bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "1, 2, 4 or 8. Number of DL antennas.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "1, 2, 4 or 8. Number of UL antennas.",
"type": "number",
"default": 2
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"ssb_pos_bitmap": {
"title": "SSB Position Bitmap",
"description": "SSB position bitmap in bits (4, 8 or 64 bits depending on the DL frequency).",
"type": "string",
"default": 10000000
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID",
"type": "number",
"default": 500
},
"cell_id": {
"title": "Cell ID",
"description": "Cell ID",
"type": "string",
"default": "0x01"
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"gnb_id": {
"title": "gNB ID",
"description": "gNB ID",
"type": "string",
"default": "0x12345"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number",
"default": 28
},
"amf_list": {
"title": "AMF list",
"description": "Optionnal. List of AMF to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"amf_addr": {
"title": "AMF Address",
"description": "IP address (and optional port) of NGAP SCTP connection to the AMF. The default port is 38412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the gNodeB, at most 12 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"tac": {
"default": 100,
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
},
"ranac": {
"title": "Optional integer (range 0 to 255)",
"description": "RAN Area Code",
"type": "number"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nssai": {
"title": "AMF slices configuration",
"description": "AMF slices configuration.",
"patternProperties": {
".*": {
"properties": {
"sst": {
"default": 1,
"title": "Slice Service Type",
"description": "Integer (range 1 to 255).",
"type": "number"
},
"sd": {
"default": "0x000032",
"title": "Slice Differentiator",
"description": "Optional integer (range 0 to 0xFFFFFE)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nr_handover_a3_offset": {
"title": "A3 offset for NR handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"nr_handover_time_to_trigger": {
"title": "Time to Trigger for NR handover",
"description": "Time to triger after which NR handover will be triggerd if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 100
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"nr_cell_id": {
"title": "NR Cell ID",
"description": "Concatenation of gnb_id and cell_id of the neighbour cell",
"type": "string"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"xn_peers": {
"title": "XN Peers",
"description": "XN Peers",
"patternProperties": {
".*": {
"properties": {
"xn_addr": {
"title": "XN Address",
"description": "XN Address of the neighbour cell (gNB Address)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"gnb_stats_fetch_period": {
"title": "gNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get gNB statistics",
"type": "number",
"default": 60
},
"gnb_drb_stats_enabled": {
"title": "Enable gNB drb statistics",
"description": "Enable gNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR ARFCN, you can retrieve from ENB/GNB side",
"type": "number"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"nr_bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "1 or 2. Number of DL antennas.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "1 or 2. Number of UL antennas.",
"type": "number",
"default": 2
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"ssb_pos_bitmap": {
"title": "SSB Position Bitmap",
"description": "SSB position bitmap in bits (4, 8 or 64 bits depending on the DL frequency).",
"type": "string",
"default": 10000000
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID",
"type": "number",
"default": 500
},
"cell_id": {
"title": "Cell ID",
"description": "Cell ID",
"type": "string",
"default": "0x01"
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"gnb_id": {
"title": "gNB ID",
"description": "gNB ID",
"type": "string",
"default": "0x12345"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number",
"default": 28
},
"amf_list": {
"title": "AMF list",
"description": "Optionnal. List of AMF to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"amf_addr": {
"title": "AMF Address",
"description": "IP address (and optional port) of NGAP SCTP connection to the AMF. The default port is 38412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the gNodeB, at most 12 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"tac": {
"default": 100,
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
},
"ranac": {
"title": "Optional integer (range 0 to 255)",
"description": "RAN Area Code",
"type": "number"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nssai": {
"title": "AMF slices configuration",
"description": "AMF slices configuration.",
"patternProperties": {
".*": {
"properties": {
"sst": {
"default": 1,
"title": "Slice Service Type",
"description": "Integer (range 1 to 255).",
"type": "number"
},
"sd": {
"default": "0x000032",
"title": "Slice Differentiator",
"description": "Optional integer (range 0 to 0xFFFFFE)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nr_handover_a3_offset": {
"title": "A3 offset for NR handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"nr_handover_time_to_trigger": {
"title": "Time to Trigger for NR handover",
"description": "Time to triger after which NR handover will be triggerd if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 100
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"nr_cell_id": {
"title": "NR Cell ID",
"description": "Concatenation of gnb_id and cell_id of the neighbour cell",
"type": "string"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"xn_peers": {
"title": "XN Peers",
"description": "XN Peers",
"patternProperties": {
".*": {
"properties": {
"xn_addr": {
"title": "XN Address",
"description": "XN Address of the neighbour cell (gNB Address)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"gnb_stats_fetch_period": {
"title": "gNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get gNB statistics",
"type": "number",
"default": 60
},
"gnb_drb_stats_enabled": {
"title": "Enable gNB drb statistics",
"description": "Enable gNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR ARFCN, you can retrieve from ENB/GNB side",
"type": "number"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR ARFCN, you can retrieve from ENB/GNB side",
"type": "number"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"nr_bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": {{ default_nr_bandwidth }}
},
"n_antenna_dl": {
"title": "Number of DL antennas",
{%- if bbu == 'ors' %}
"description": "1 or 2. Number of DL antennas.",
{%- else %}
"description": "1, 2, 4 or 8. Number of DL antennas.",
{%- endif %}
"type": "number",
"default": {{ default_n_antenna_dl }}
},
"n_antenna_ul": {
"title": "Number of UL antennas",
{%- if bbu == 'ors' %}
"description": "1 or 2. Number of UL antennas.",
{%- else %}
"description": "1, 2, 4 or 8. Number of UL antennas.",
{%- endif %}
"type": "number",
"default": {{ default_n_antenna_ul }}
},
{%- if rf_mode == 'tdd' %}
"tdd_ul_dl_config": {
"title": "TDD",
"description": "TDD",
"type": "string",
"enum": [
"5ms 2UL 7DL 4/6 (default)",
"2.5ms 1UL 3DL 2/10",
"5ms 8UL 1DL 2/10 (maximum uplink)"
],
"default": "5ms 2UL 7DL 4/6 (default)"
},
{%- endif %}
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"ssb_pos_bitmap": {
"title": "SSB Position Bitmap",
"description": "SSB position bitmap in bits (4, 8 or 64 bits depending on the DL frequency).",
"type": "string",
"default": {{ default_nr_ssb_pos_bitmap }}
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID",
"type": "number",
"default": 500
},
"cell_id": {
"title": "Cell ID",
"description": "Cell ID",
"type": "string",
"default": "0x01"
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"gnb_id": {
"title": "gNB ID",
"description": "gNB ID",
"type": "string",
"default": "0x12345"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number",
"default": 28
},
"amf_list": {
"title": "AMF list",
"description": "Optionnal. List of AMF to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"amf_addr": {
"title": "AMF Address",
"description": "IP address (and optional port) of NGAP SCTP connection to the AMF. The default port is 38412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the gNodeB, at most 12 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"tac": {
"default": 100,
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
},
"ranac": {
"title": "Optional integer (range 0 to 255)",
"description": "RAN Area Code",
"type": "number"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nssai": {
"title": "AMF slices configuration",
"description": "AMF slices configuration.",
"patternProperties": {
".*": {
"properties": {
"sst": {
"default": 1,
"title": "Slice Service Type",
"description": "Integer (range 1 to 255).",
"type": "number"
},
"sd": {
"default": "0x000032",
"title": "Slice Differentiator",
"description": "Optional integer (range 0 to 0xFFFFFE)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nr_handover_a3_offset": {
"title": "A3 offset for NR handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"nr_handover_time_to_trigger": {
"title": "Time to Trigger for NR handover",
"description": "Time to triger after which NR handover will be triggerd if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 100
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"nr_cell_id": {
"title": "NR Cell ID",
"description": "Concatenation of gnb_id and cell_id of the neighbour cell",
"type": "string"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"xn_peers": {
"title": "XN Peers",
"description": "XN Peers",
"patternProperties": {
".*": {
"properties": {
"xn_addr": {
"title": "XN Address",
"description": "XN Address of the neighbour cell (gNB Address)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": {{ default_nr_inactivity_timer }}
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"gnb_stats_fetch_period": {
"title": "gNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get gNB statistics",
"type": "number",
"default": 60
},
"gnb_drb_stats_enabled": {
"title": "Enable gNB drb statistics",
"description": "Enable gNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
...@@ -18,117 +18,78 @@ ...@@ -18,117 +18,78 @@
"default": "20 MHz" "default": "20 MHz"
}, },
"n_antenna_dl": { "n_antenna_dl": {
"title": "Number of DL antennas", "$ref": "ru/common.json#/properties/n_antenna_dl",
"description": "1 or 2. Number of DL antennas.", "enum": [
"type": "number", 1,
2
],
"default": 2 "default": 2
}, },
"n_antenna_ul": { "n_antenna_ul": {
"title": "Number of UL antennas", "$ref": "ru/common.json#/properties/n_antenna_ul",
"description": "1 or 2. Number of UL antennas.", "enum": [
"type": "number", 1,
2
],
"default": 2 "default": 2
}, },
"rf_mode": {
"$ref": "cell/common.json#/properties/rf_mode",
"default": "tdd"
},
"tdd_ul_dl_config": {
"$ref": "cell/lte/input-schema.json#/properties/tdd_ul_dl_config"
},
"dl_earfcn": { "dl_earfcn": {
"title": "DL EARFCN", "$ref": "cell/lte/input-schema.json#/properties/dl_earfcn"
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
}, },
"pci": { "pci": {
"title": "Physical Cell ID", "$ref": "cell/common.json#/properties/pci",
"description": "Physical Cell ID",
"type": "number",
"default": 1 "default": 1
}, },
"cell_id": { "cell_id": {
"title": "Cell ID", "$ref": "cell/common.json#/properties/cell_id",
"description": "Cell ID",
"type": "string",
"default": "0x01" "default": "0x01"
}, },
"tac": { "tac": {
"title": "Tracking Area Code", "$ref": "cell/lte/input-schema.json#/properties/tac",
"description": "Tracking Area Code in hexadecimal representation (range 0x0000 to 0xffff)", "default": "0x0001"
"default": "0x0001",
"type": "string"
}, },
"root_sequence_index": { "root_sequence_index": {
"title": "Root Sequence Index", "$ref": "cell/common.json#/properties/root_sequence_index",
"description": "Range: 0 to 837. Set the PRACH root sequence index (SIB2.rootSequenceIndex field). It must be different for each neighbour cell operating on the same frequency and sharing the same PRACH configuration.",
"type": "number",
"default": 204 "default": 204
}, },
"tx_gain": { "tx_gain": {
"title": "Tx gain", "$ref": "ru/common.json#/properties/tx_gain"
"description": "Tx gain (in dB)",
"type": "number"
}, },
"rx_gain": { "rx_gain": {
"title": "Rx gain", "$ref": "ru/common.json#/properties/rx_gain"
"description": "Rx gain (in dB)",
"type": "number"
}, },
"enb_id": { "enb_id": {
"title": "eNB ID", "$ref": "instance-enb-input-schema.json#/properties/enb_id",
"description": "eNB ID",
"type": "string",
"default": "0x1A2D0" "default": "0x1A2D0"
}, },
"gtp_addr": { "gtp_addr": {
"title": "GTP Address", "$ref": "instance-enb-input-schema.json#/properties/gtp_addr",
"description": "String. Set the IP address (and optional port) on which the GTP-U packets are received. The default port is 2152. It is normally the IP address of the network interface connected to the core network.",
"type": "string",
"default": "127.0.1.1" "default": "127.0.1.1"
}, },
"mme_list": { "mme_list": {
"title": "MME list", "$ref": "instance-enb-input-schema.json#/properties/mme_list",
"description": "Optionnal. List of MME to which the gNodeB is connected", "default": {
"patternProperties": { "1": {
".*": { "mme_addr": "127.0.1.100"
"properties": {
"mme_addr": {
"title": "MME Address",
"description": "IP address (and optional port) of S1AP SCTP connection to the MME. The default port is 36412.",
"type": "string"
} }
},
"type": "object"
} }
}, },
"type": "object",
"default": {}
},
"plmn_list": { "plmn_list": {
"title": "PLMN list", "$ref": "instance-enb-input-schema.json#/properties/plmn_list",
"description": "List of PLMNs broadcasted by the eNodeB, at most 6 (default: 00101)", "description": "List of PLMNs broadcasted by the eNodeB, at most 6 (default: 00101)",
"patternProperties": { "default": {
".*": { "1": {
"properties": { "plmn": "00101"
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"attach_without_pdn": {
"default": false,
"title": "Attach Without PDN",
"description": "Optional boolean. Indicates if PLMN supports attach without PDN connectivity.",
"type": "boolean"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
} }
},
"type": "object"
} }
}, },
"type": "object",
"default": {}
},
"lte_handover_a3_offset": { "lte_handover_a3_offset": {
"title": "A3 offset for LTE handover", "title": "A3 offset for LTE handover",
"description": "RSRP gain offset between gNBs which will trigger handover", "description": "RSRP gain offset between gNBs which will trigger handover",
...@@ -166,24 +127,33 @@ ...@@ -166,24 +127,33 @@
".*": { ".*": {
"properties": { "properties": {
"dl_earfcn": { "dl_earfcn": {
"title": "DL EARFCN", "$ref": "peer/cell/lte/input-schema.json#/properties/dl_earfcn"
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
}, },
"pci": { "pci": {
"title": "Physical Cell ID", "$ref": "peer/cell/lte/input-schema.json#/properties/pci"
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
}, },
"cell_id": { "cell_id": {
"title": "Cell ID", "$ref": "peer/cell/lte/input-schema.json#/properties/e_cell_id"
"description": "Concatenation of enb_id and cell_id of the neighbour cell",
"type": "string"
}, },
"tac": { "tac": {
"title": "Tracking Area Code", "$ref": "peer/cell/lte/input-schema.json#/properties/tac",
"description": "Integer (range 0 to 16777215)", "default": "0x0001"
"type": "number" }
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"x2_peers": {
"title": "X2 Peers",
"description": "X2 Peers",
"patternProperties": {
".*": {
"properties": {
"x2_addr": {
"$ref": "peer/lte/input-schema.json#/properties/x2_addr"
} }
}, },
"type": "object" "type": "object"
...@@ -193,27 +163,17 @@ ...@@ -193,27 +163,17 @@
"default": {} "default": {}
}, },
"websocket_password": { "websocket_password": {
"title": "Websocket password", "$ref": "instance-enb-input-schema.json#/properties/websocket_password"
"description": "Activates websocket for remote control and sets password",
"type": "string"
}, },
"inactivity_timer": { "inactivity_timer": {
"title": "Inactivity Timer", "$ref": "cell/common.json#/properties/inactivity_timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000 "default": 10000
}, },
"log_phy_debug": { "log_phy_debug": {
"title": "Physical layer log debug", "$ref": "instance-enb-input-schema.json#/properties/log_phy_debug"
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
}, },
"gps_sync": { "gps_sync": {
"default": false, "$ref": "instance-enb-input-schema.json#/properties/gps_sync"
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
}, },
"disable_sdr": { "disable_sdr": {
"default": false, "default": false,
...@@ -222,49 +182,28 @@ ...@@ -222,49 +182,28 @@
"type": "boolean" "type": "boolean"
}, },
"use_ipv4": { "use_ipv4": {
"default": false, "$ref": "instance-enb-input-schema.json#/properties/use_ipv4"
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
}, },
"enb_stats_fetch_period": { "enb_stats_fetch_period": {
"title": "eNB statistics fetch period (seconds)", "$ref": "instance-enb-input-schema.json#/properties/enb_stats_fetch_period"
"description": "Describes how often a call to Amarisoft remote API is made to get eNB statistics",
"type": "number",
"default": 60
}, },
"enb_drb_stats_enabled": { "enb_drb_stats_enabled": {
"title": "Enable eNB drb statistics", "$ref": "instance-enb-input-schema.json#/properties/enb_drb_stats_enabled"
"description": "Enable eNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
}, },
"max_rx_sample_db": { "max_rx_sample_db": {
"title": "Maximum RX sample value (dB)", "$ref": "instance-enb-input-schema.json#/properties/max_rx_sample_db"
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
}, },
"min_rxtx_delay": { "min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)", "$ref": "instance-enb-input-schema.json#/properties/min_rxtx_delay"
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
}, },
"xlog_fluentbit_forward_host": { "xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit", "$ref": "instance-enb-input-schema.json#/properties/xlog_fluentbit_forward_host"
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
}, },
"xlog_fluentbit_forward_port": { "xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit", "$ref": "instance-enb-input-schema.json#/properties/xlog_fluentbit_forward_port"
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
}, },
"xlog_fluentbit_forward_shared_key": { "xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit", "$ref": "instance-enb-input-schema.json#/properties/xlog_fluentbit_forward_shared_key"
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
} }
} }
} }
{
"$schema": "http://json-schema.org/draft-04/schema",
"description": "Values returned by ORS eNB instantiation (stub)",
"type": "object",
"properties": {}
}
# instance-ors-enb translates ORS enb/gnb into base enb/gnb. # instance-ors-enb translates ORS enb/gnb into generic enb with 1 SDR RU and 1 CELL.
{#- enb_mode indicates with which mode ors' enb is instantiated with - enb | gnb #} {#- enb_mode indicates with which mode ors' enb is instantiated with - enb | gnb #}
{%- set enb_mode = slap_configuration['slap-software-type'] %} {%- set enb_mode = slap_configuration['slap-software-type'] %}
{%- do assert(enb_mode in ('enb', 'gnb'), enb_mode) %} {%- do assert(enb_mode in ('enb', 'gnb'), enb_mode) %}
{#- defaults for ORS parameters.
TODO automatically load ORS/enb and ORS/gnb defaults from JSON schema #}
{%- set ors_enb_defaults = {
"bandwidth": "20 MHz",
"n_antenna_dl": 2,
"n_antenna_ul": 2,
"rf_mode": "tdd",
"tdd_ul_dl_config": "[Configuration 2] 5ms 2UL 6DL (default)",
"pci": 1,
"cell_id": "0x01",
"tac": "0x0001",
"root_sequence_index": 204,
"enb_id": "0x1A2D0",
"mme_list": {'1': {'mme_addr': '127.0.1.100'}},
"plmn_list": {"1": {'plmn': '00101'}},
"ncell_list": {},
"x2_peers": {},
"inactivity_timer": 10000,
"disable_sdr": false
} %}
{%- set ors_gnb_defaults = {
"nr_bandwidth": 40,
"n_antenna_dl": 2,
"n_antenna_ul": 2,
"rf_mode": "tdd",
"tdd_ul_dl_config": "5ms 2UL 7DL 4/6 (default)",
"ssb_pos_bitmap": "10000000",
"pci": 500,
"cell_id": "0x01",
"gnb_id": "0x12345",
"gnb_id_bits": 28,
"amf_list": {'1': {'amf_addr': '127.0.1.100'}},
"plmn_list": {'1': {'plmn': '00101', 'tac': 100}},
"ncell_list": {},
"xn_peers": {},
"inactivity_timer": 10000,
"disable_sdr": false
} %}
{#- inject ORS defaults #} {%- set ors_defaults = {'enb': ors_enb_defaults, 'gnb': ors_gnb_defaults} [enb_mode] %}
{%- do RF.setdefault('tx_gain', ors_version['current-tx-gain']) %} {%- for k,v in ors_defaults|dictsort %}
{%- do RF.setdefault('rx_gain', ors_version['current-rx-gain']) %} {%- do slapparameter_dict.setdefault(k, v) %}
{%- do RF.setdefault('earfcn', ors_version['current-earfcn']) %} {%- endfor %}
{%- do RF.setdefault('nr_arfcn', ors_version['current-nr-arfcn']) %}
{%- do RF.setdefault('nr_band', ors_version['current-nr-band']) %}
{#- make real ru/cell/peer/... shared instances to be rejected in ORS mode #}
{%- set ishared_list = slap_configuration.setdefault('slave-instance-list', []) %}
{%- for ishared in ishared_list %}
{%- set _ = json_module.loads(ishared['_']) %}
{%- if 'ru_type' in _ or 'cell_type' in _ %}
{%- do ishared.update({'_': {'REJECT': 1}|tojson}) %}
{%- endif %}
{%- endfor %}
{#- inject ru+cell synthesized from ORS-specific parameters #}
{%- 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_link_type': 'sdr',
'sdr_dev_list': [0],
'n_antenna_dl': slapparameter_dict.n_antenna_dl,
'n_antenna_ul': slapparameter_dict.n_antenna_ul,
'tx_gain': ors_version['current-tx-gain'],
'rx_gain': ors_version['current-rx-gain'],
'txrx_active': 'ACTIVE' if (not slapparameter_dict.disable_sdr) else 'INACTIVE',
} |tojson
})
%}
{%- if enb_mode == 'enb' %}
{%- set cell = {
'cell_type': 'lte',
'dl_earfcn': ors_version['current-earfcn'],
'bandwidth': float(slapparameter_dict.bandwidth.removesuffix(' MHz')),
'tac': slapparameter_dict.tac,
'root_sequence_index': slapparameter_dict.root_sequence_index,
}
%}
{%- elif enb_mode == 'gnb' %}
{%- set cell = {
'cell_type': 'nr',
'dl_nr_arfcn': ors_version['current-nr-arfcn'],
'nr_band': ors_version['current-nr-band'],
'bandwidth': slapparameter_dict.nr_bandwidth,
'ssb_pos_bitmap': slapparameter_dict.ssb_pos_bitmap,
'root_sequence_index': 1,
}
%}
{%- endif %}
{%- do cell.update({
'cell_kind': 'enb',
'rf_mode': slapparameter_dict.rf_mode,
'pci': slapparameter_dict.pci,
'cell_id': slapparameter_dict.cell_id,
'tdd_ul_dl_config': slapparameter_dict.tdd_ul_dl_config,
'inactivity_timer': slapparameter_dict.inactivity_timer,
'ru': { 'ru_type': 'ru_ref',
'ru_ref': iref('RU') }
})
%}
{%- do ishared_list.append({
'slave_title': iref('CELL'),
'slave_reference': False,
'_': cell | tojson
})
%}
{#- inject synthesized peer cells #}
{%- for k, ncell in slapparameter_dict.ncell_list|dictsort %}
{%- set peercell = {'cell_kind': 'enb_peer'} %}
{%- macro _(name, default) %}
{%- if default is defined %}
{%- do peercell.update({name: default}) %}
{%- endif %}
{%- if name in ncell %}
{%- do peercell.update({name: ncell[name]}) %}
{%- endif %}
{%- endmacro %}
{%- if enb_mode == 'enb' %}
{%- do peercell.update({'cell_type': 'lte'}) %}
{%- if 'cell_id' in ncell %}
{%- do peercell.update({'e_cell_id': ncell.cell_id}) %}
{%- endif %}
{%- do _('pci') %}
{%- do _('dl_earfcn') %}
{%- do _('tac', '0x0001') %}
{%- elif enb_mode == 'gnb' %}
{%- do peercell.update({'cell_type': 'nr'}) %}
{%- do _('nr_cell_id') %}
{%- do _('gnb_id_bits') %}
{%- do _('pci') %}
{%- do _('dl_nr_arfcn') %}
{%- do _('ssb_nr_arfcn') %}
{%- do _('tac', 1) %}
{%- do _('nr_band') %}
{%- endif %}
{%- do ishared_list.append({
'slave_title': '%s%s' % (iref('PEERCELL'), k),
'slave_reference': False,
'_': peercell | tojson
})
%}
{%- endfor %}
{#- inject synthesized peers #}
{%- if enb_mode == 'lte' %}
{%- for k, peer in slapparameter_dict.x2_peers|dictsort %}
{%- do ishared_list.append({
'slave_title': '%s%s' % (iref('X2_PEER'), k),
'slave_reference': False,
'_': {
'peer_type': 'nr',
'x2_addr': peer.x2_addr,
} | tojson
})
%}
{%- endfor %}
{%- elif enb_mode == 'nr' %}
{%- for k, peer in slapparameter_dict.xn_peers|dictsort %}
{%- do ishared_list.append({
'slave_title': '%s%s' % (iref('XN_PEER'), k),
'slave_reference': False,
'_': {
'peer_type': 'nr',
'xn_addr': peer.xn_addr
} | tojson
})
%}
{%- endfor %}
{%- endif %}
{#- gnb: plmn_list -> plmn_list_5g #}
{%- if enb_mode == 'gnb' %}
{%- set _ = slapparameter_dict %}
{%- do _.update({'plmn_list_5g': _.plmn_list}) %}
{%- do _.pop('plmn_list') %}
{%- endif %}
{#- backward compatibility: if ORS is running in gnb mode, and gnb_* parameters {#- backward compatibility: if ORS is running in gnb mode, and gnb_* parameters
...@@ -32,7 +214,7 @@ ...@@ -32,7 +214,7 @@
{%- endif %} {%- endif %}
# code of base enb # code of generic enb
{% include 'instance-enb-base.jinja2.cfg' %} {% include 'instance-enb-base.jinja2.cfg' %}
...@@ -59,3 +241,16 @@ current-earfcn = {{ ors_version['current-earfcn'] }} ...@@ -59,3 +241,16 @@ current-earfcn = {{ ors_version['current-earfcn'] }}
current-nr-arfcn = {{ ors_version['current-nr-arfcn'] }} current-nr-arfcn = {{ ors_version['current-nr-arfcn'] }}
current-nr-band = {{ ors_version['current-nr-band'] }} current-nr-band = {{ ors_version['current-nr-band'] }}
{%- endif %} {%- endif %}
# hide ru-list, cell-list, peer-list and peer-cell-list from published information
[publish-connection-information]
depends += ${publish-connection-information-ors-cleanup:recipe}
[publish-connection-information-ors-cleanup]
recipe = slapos.recipe.build
init =
publish = self.buildout['publish-connection-information']
del publish['ru-list']
del publish['cell-list']
del publish['peer-list']
del publish['peer-cell-list']
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"nr_bandwidth": {
"$ref": "cell/common.json#/properties/bandwidth",
"default": 40
},
"n_antenna_dl": {
"$ref": "instance-ors-enb-input-schema.json#/properties/n_antenna_dl"
},
"n_antenna_ul": {
"$ref": "instance-ors-enb-input-schema.json#/properties/n_antenna_ul"
},
"rf_mode": {
"$ref": "instance-ors-enb-input-schema.json#/properties/rf_mode"
},
"tdd_ul_dl_config": {
"$ref": "cell/nr/input-schema.json#/properties/tdd_ul_dl_config"
},
"dl_nr_arfcn": {
"$ref": "cell/nr/input-schema.json#/properties/dl_nr_arfcn"
},
"nr_band": {
"$ref": "cell/nr/input-schema.json#/properties/nr_band"
},
"ssb_pos_bitmap": {
"$ref": "cell/nr/input-schema.json#/properties/ssb_pos_bitmap",
"default": "10000000"
},
"pci": {
"$ref": "cell/common.json#/properties/pci",
"default": 500
},
"cell_id": {
"$ref": "instance-ors-enb-input-schema.json#/properties/cell_id"
},
"tx_gain": {
"$ref": "instance-ors-enb-input-schema.json#/properties/tx_gain"
},
"rx_gain": {
"$ref": "instance-ors-enb-input-schema.json#/properties/rx_gain"
},
"gnb_id": {
"$ref": "instance-enb-input-schema.json#/properties/gnb_id",
"default": "0x12345"
},
"gnb_id_bits": {
"$ref": "instance-enb-input-schema.json#/properties/gnb_id_bits",
"default": 28
},
"amf_list": {
"$ref": "instance-enb-input-schema.json#/properties/amf_list",
"default": {
"1": {
"amf_addr": "127.0.1.100"
}
}
},
"plmn_list": {
"$ref": "instance-enb-input-schema.json#/properties/plmn_list_5g",
"description": "List of PLMNs broadcasted by the gNodeB, at most 12 (default: 00101)",
"default": {
"1": {
"plmn": "00101",
"tac": 100
}
}
},
"nssai": {
"$ref": "instance-enb-input-schema.json#/properties/nssai"
},
"nr_handover_a3_offset": {
"title": "A3 offset for NR handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"nr_handover_time_to_trigger": {
"title": "Time to Trigger for NR handover",
"description": "Time to triger after which NR handover will be triggerd if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 100
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_nr_arfcn": {
"$ref": "peer/cell/nr/input-schema.json#/properties/dl_nr_arfcn"
},
"ssb_nr_arfcn": {
"$ref": "peer/cell/nr/input-schema.json#/properties/ssb_nr_arfcn"
},
"pci": {
"$ref": "peer/cell/nr/input-schema.json#/properties/pci"
},
"nr_cell_id": {
"$ref": "peer/cell/nr/input-schema.json#/properties/nr_cell_id"
},
"gnb_id_bits": {
"$ref": "peer/cell/nr/input-schema.json#/properties/gnb_id_bits"
},
"nr_band": {
"$ref": "peer/cell/nr/input-schema.json#/properties/nr_band"
},
"tac": {
"$ref": "peer/cell/nr/input-schema.json#/properties/tac",
"default": 1
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"xn_peers": {
"title": "XN Peers",
"description": "XN Peers",
"patternProperties": {
".*": {
"properties": {
"xn_addr": {
"$ref": "peer/nr/input-schema.json#/properties/xn_addr"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"$ref": "instance-ors-enb-input-schema.json#/properties/websocket_password"
},
"inactivity_timer": {
"$ref": "instance-ors-enb-input-schema.json#/properties/inactivity_timer"
},
"log_phy_debug": {
"$ref": "instance-ors-enb-input-schema.json#/properties/log_phy_debug"
},
"gps_sync": {
"$ref": "instance-ors-enb-input-schema.json#/properties/gps_sync"
},
"disable_sdr": {
"$ref": "instance-ors-enb-input-schema.json#/properties/disable_sdr"
},
"use_ipv4": {
"$ref": "instance-ors-enb-input-schema.json#/properties/use_ipv4"
},
"enb_stats_fetch_period": {
"$ref": "instance-ors-enb-input-schema.json#/properties/enb_stats_fetch_period"
},
"enb_drb_stats_enabled": {
"$ref": "instance-ors-enb-input-schema.json#/properties/enb_drb_stats_enabled"
},
"max_rx_sample_db": {
"$ref": "instance-ors-enb-input-schema.json#/properties/max_rx_sample_db"
},
"min_rxtx_delay": {
"$ref": "instance-ors-enb-input-schema.json#/properties/min_rxtx_delay"
},
"xlog_fluentbit_forward_host": {
"$ref": "instance-ors-enb-input-schema.json#/properties/xlog_fluentbit_forward_host"
},
"xlog_fluentbit_forward_port": {
"$ref": "instance-ors-enb-input-schema.json#/properties/xlog_fluentbit_forward_port"
},
"xlog_fluentbit_forward_shared_key": {
"$ref": "instance-ors-enb-input-schema.json#/properties/xlog_fluentbit_forward_shared_key"
}
}
}
{
"$schema": "http://json-schema.org/draft-04/schema",
"description": "Values returned by ORS gNB instantiation (stub)",
"type": "object",
"properties": {}
}
...@@ -10,8 +10,7 @@ enb-epc = $${:obsolete} ...@@ -10,8 +10,7 @@ enb-epc = $${:obsolete}
gnb-epc = $${:obsolete} gnb-epc = $${:obsolete}
epc = $${:obsolete} epc = $${:obsolete}
mme = $${:obsolete} mme = $${:obsolete}
ue-lte = ue =
ue-nr =
[dynamic-template-obsolete] [dynamic-template-obsolete]
< = jinja2-template-base < = jinja2-template-base
...@@ -22,7 +21,8 @@ extra-context = ...@@ -22,7 +21,8 @@ extra-context =
key slave_instance_list slap-configuration:slave-instance-list key slave_instance_list slap-configuration:slave-instance-list
# ORS-specific enb and gnb # ORS-specific enb and gnb
# both are served by instance-ors-enb # both are served by instance-ors-enb, which translates
# ORS enb/gnb schemas to generic enb with only one RU and one LTE or NR CELL
[dynamic-template-ors-enb] [dynamic-template-ors-enb]
< = dynamic-template-enb < = dynamic-template-enb
url = ${template-ors-enb:target} url = ${template-ors-enb:target}
......
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "1, 2, 4 or 8. Number of DL antennas.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "1, 2, 4 or 8. Number of UL antennas.",
"type": "number",
"default": 2
},
"tdd_ul_dl_config": {
"title": "TDD",
"description": "TDD",
"type": "string",
"enum": [
"[Configuration 2] 5ms 2UL 6DL (default)",
"[Configuration 6] 5ms 5UL 3DL (maximum uplink)"
],
"default": "5ms 2UL 7DL 4/6 (default)"
},
"sdr_number": {
"title": "SDR Number",
"description": "SDR Number",
"type": "number",
"default": 0
},
"cpri_port": {
"title": "CPRI Port Number",
"description": "CPRI Port Number",
"type": "number",
"default": 0
},
"cell_list": {
"title": "Cell List",
"description": "Cell List",
"patternProperties": {
".*": {
"properties": {
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell IDs",
"type": "number"
},
"cell_id": {
"title": "Cell ID",
"description": "Cell IDs",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"enb_id": {
"title": "eNB ID",
"description": "eNB ID",
"type": "string",
"default": "0x1A2D0"
},
"gtp_addr": {
"title": "GTP Address",
"description": "String. Set the IP address (and optional port) on which the GTP-U packets are received. The default port is 2152. It is normally the IP address of the network interface connected to the core network.",
"type": "string",
"default": "127.0.1.1"
},
"mme_list": {
"title": "MME list",
"description": "Optionnal. List of MME to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"mme_addr": {
"title": "MME Address",
"description": "IP address (and optional port) of S1AP SCTP connection to the MME. The default port is 36412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the eNodeB, at most 6 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"attach_without_pdn": {
"default": false,
"title": "Attach Without PDN",
"description": "Optional boolean. Indicates if PLMN supports attach without PDN connectivity.",
"type": "boolean"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"lte_handover_a3_offset": {
"title": "A3 offset for LTE handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"lte_handover_time_to_trigger": {
"title": "Time to Trigger for LTE handover",
"description": "Time to triger after which LTE handover will be triggered if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 480
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"cell_id": {
"title": "Cell ID",
"description": "Concatenation of enb_id and cell_id of the neighbour cell",
"type": "string"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"enb_stats_fetch_period": {
"title": "eNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get eNB statistics",
"type": "number",
"default": 60
},
"enb_drb_stats_enabled": {
"title": "Enable eNB drb statistics",
"description": "Enable eNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"nr_bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "1, 2, 4 or 8. Number of DL antennas.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "1, 2, 4 or 8. Number of UL antennas.",
"type": "number",
"default": 2
},
"tdd_ul_dl_config": {
"title": "TDD",
"description": "TDD",
"type": "string",
"enum": [
"5ms 2UL 7DL 4/6 (default)",
"2.5ms 1UL 3DL 2/10",
"5ms 8UL 1DL 2/10 (maximum uplink)"
],
"default": "5ms 2UL 7DL 4/6 (default)"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"ssb_pos_bitmap": {
"title": "SSB Position Bitmap",
"description": "SSB position bitmap in bits (4, 8 or 64 bits depending on the DL frequency).",
"type": "string",
"default": 10000000
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID",
"type": "number",
"default": 500
},
"cell_id": {
"title": "Cell ID",
"description": "Cell ID",
"type": "string",
"default": "0x01"
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"gnb_id": {
"title": "gNB ID",
"description": "gNB ID",
"type": "string",
"default": "0x12345"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number",
"default": 28
},
"amf_list": {
"title": "AMF list",
"description": "Optionnal. List of AMF to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"amf_addr": {
"title": "AMF Address",
"description": "IP address (and optional port) of NGAP SCTP connection to the AMF. The default port is 38412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the gNodeB, at most 12 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"tac": {
"default": 100,
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
},
"ranac": {
"title": "Optional integer (range 0 to 255)",
"description": "RAN Area Code",
"type": "number"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nssai": {
"title": "AMF slices configuration",
"description": "AMF slices configuration.",
"patternProperties": {
".*": {
"properties": {
"sst": {
"default": 1,
"title": "Slice Service Type",
"description": "Integer (range 1 to 255).",
"type": "number"
},
"sd": {
"default": "0x000032",
"title": "Slice Differentiator",
"description": "Optional integer (range 0 to 0xFFFFFE)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nr_handover_a3_offset": {
"title": "A3 offset for NR handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"nr_handover_time_to_trigger": {
"title": "Time to Trigger for NR handover",
"description": "Time to triger after which NR handover will be triggerd if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 100
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"nr_cell_id": {
"title": "NR Cell ID",
"description": "Concatenation of gnb_id and cell_id of the neighbour cell",
"type": "string"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"xn_peers": {
"title": "XN Peers",
"description": "XN Peers",
"patternProperties": {
".*": {
"properties": {
"xn_addr": {
"title": "XN Address",
"description": "XN Address of the neighbour cell (gNB Address)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"gnb_stats_fetch_period": {
"title": "gNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get gNB statistics",
"type": "number",
"default": 60
},
"gnb_drb_stats_enabled": {
"title": "Enable gNB drb statistics",
"description": "Enable gNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "1, 2, 4 or 8. Number of DL antennas.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "1, 2, 4 or 8. Number of UL antennas.",
"type": "number",
"default": 2
},
"tdd_ul_dl_config": {
"title": "TDD",
"description": "TDD",
"type": "string",
"enum": [
"[Configuration 2] 5ms 2UL 6DL (default)",
"[Configuration 6] 5ms 5UL 3DL (maximum uplink)"
],
"default": "5ms 2UL 7DL 4/6 (default)"
},
"sdr_number": {
"title": "SDR Number",
"description": "SDR Number",
"type": "number",
"default": 0
},
"cpri_port": {
"title": "CPRI Port Number",
"description": "CPRI Port Number",
"type": "number",
"default": 0
},
"cpri_mult": {
"title": "CPRI Mult",
"description": "Select the CPRI line bit rate in terms of multiple of option 1 (614.4 Mbps). E.g set 4 for option 3, 8 for option 5 and 16 for option 7.",
"type": "number",
"default": 16,
"enum": [
4,
5,
8,
16
]
},
"cell_list": {
"title": "Cell List",
"description": "Cell List",
"patternProperties": {
".*": {
"properties": {
"cpri_rx_delay": {
"title": "CPRI RX Delay",
"description": "Delays between TX and RX position in CPRI frame. This should be set to the value of (T2a + T3a - Toffset) provided by the RRH specification.",
"type": "number",
"default": 25.11
},
"cpri_tx_delay": {
"title": "CPRI TX Delay",
"description": "Advances Start of Frame relative to PPS to compensate for delays in transmit line and RRH. This should be set to T12 + T2a.",
"type": "number",
"default": 14.71
},
"cpri_tx_dbm": {
"title": "CPRI TX dBm",
"description": "Optional floating points value in dBm (default 0). Needed by ENB/GNB to have a notion of actual output power. Computed from maximum power output of the RRH for a 0dBFS input signal (full scale). ",
"type": "number",
"default": 63
},
"cpri_port_number": {
"title": "CPRI Port Number",
"description": "CPRI Port Number",
"type": "number",
"default": 0
},
"ru_mac_addr": {
"title": "RU MAC address",
"description": "RU MAC address used for NETCONF",
"type": "string"
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell IDs",
"type": "number"
},
"cell_id": {
"title": "Cell ID",
"description": "Cell IDs",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"enb_id": {
"title": "eNB ID",
"description": "eNB ID",
"type": "string",
"default": "0x1A2D0"
},
"gtp_addr": {
"title": "GTP Address",
"description": "String. Set the IP address (and optional port) on which the GTP-U packets are received. The default port is 2152. It is normally the IP address of the network interface connected to the core network.",
"type": "string",
"default": "127.0.1.1"
},
"mme_list": {
"title": "MME list",
"description": "Optionnal. List of MME to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"mme_addr": {
"title": "MME Address",
"description": "IP address (and optional port) of S1AP SCTP connection to the MME. The default port is 36412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the eNodeB, at most 6 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"attach_without_pdn": {
"default": false,
"title": "Attach Without PDN",
"description": "Optional boolean. Indicates if PLMN supports attach without PDN connectivity.",
"type": "boolean"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"lte_handover_a3_offset": {
"title": "A3 offset for LTE handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"lte_handover_time_to_trigger": {
"title": "Time to Trigger for LTE handover",
"description": "Time to triger after which LTE handover will be triggered if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 480
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"cell_id": {
"title": "Cell ID",
"description": "Concatenation of enb_id and cell_id of the neighbour cell",
"type": "string"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"enb_stats_fetch_period": {
"title": "eNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get eNB statistics",
"type": "number",
"default": 60
},
"enb_drb_stats_enabled": {
"title": "Enable eNB drb statistics",
"description": "Enable eNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"nr_bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "1, 2, 4 or 8. Number of DL antennas.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "1, 2, 4 or 8. Number of UL antennas.",
"type": "number",
"default": 2
},
"tdd_ul_dl_config": {
"title": "TDD",
"description": "TDD",
"type": "string",
"enum": [
"5ms 2UL 7DL 4/6 (default)",
"2.5ms 1UL 3DL 2/10",
"5ms 8UL 1DL 2/10 (maximum uplink)"
],
"default": "5ms 2UL 7DL 4/6 (default)"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"ssb_pos_bitmap": {
"title": "SSB Position Bitmap",
"description": "SSB position bitmap in bits (4, 8 or 64 bits depending on the DL frequency).",
"type": "string",
"default": 10000000
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID",
"type": "number",
"default": 500
},
"cell_id": {
"title": "Cell ID",
"description": "Cell ID",
"type": "string",
"default": "0x01"
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"gnb_id": {
"title": "gNB ID",
"description": "gNB ID",
"type": "string",
"default": "0x12345"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number",
"default": 28
},
"amf_list": {
"title": "AMF list",
"description": "Optionnal. List of AMF to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"amf_addr": {
"title": "AMF Address",
"description": "IP address (and optional port) of NGAP SCTP connection to the AMF. The default port is 38412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the gNodeB, at most 12 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"tac": {
"default": 100,
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
},
"ranac": {
"title": "Optional integer (range 0 to 255)",
"description": "RAN Area Code",
"type": "number"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nssai": {
"title": "AMF slices configuration",
"description": "AMF slices configuration.",
"patternProperties": {
".*": {
"properties": {
"sst": {
"default": 1,
"title": "Slice Service Type",
"description": "Integer (range 1 to 255).",
"type": "number"
},
"sd": {
"default": "0x000032",
"title": "Slice Differentiator",
"description": "Optional integer (range 0 to 0xFFFFFE)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nr_handover_a3_offset": {
"title": "A3 offset for NR handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"nr_handover_time_to_trigger": {
"title": "Time to Trigger for NR handover",
"description": "Time to triger after which NR handover will be triggerd if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 100
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"nr_cell_id": {
"title": "NR Cell ID",
"description": "Concatenation of gnb_id and cell_id of the neighbour cell",
"type": "string"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"xn_peers": {
"title": "XN Peers",
"description": "XN Peers",
"patternProperties": {
".*": {
"properties": {
"xn_addr": {
"title": "XN Address",
"description": "XN Address of the neighbour cell (gNB Address)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"gnb_stats_fetch_period": {
"title": "gNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get gNB statistics",
"type": "number",
"default": 60
},
"gnb_drb_stats_enabled": {
"title": "Enable gNB drb statistics",
"description": "Enable gNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR ARFCN, you can retrieve from ENB/GNB side",
"type": "number"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "1 or 2. Number of DL antennas.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "1 or 2. Number of UL antennas.",
"type": "number",
"default": 2
},
"tdd_ul_dl_config": {
"title": "TDD",
"description": "TDD",
"type": "string",
"enum": [
"[Configuration 2] 5ms 2UL 6DL (default)",
"[Configuration 6] 5ms 5UL 3DL (maximum uplink)"
],
"default": "5ms 2UL 7DL 4/6 (default)"
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID",
"type": "number",
"default": 1
},
"cell_id": {
"title": "Cell ID",
"description": "Cell ID",
"type": "string",
"default": "0x01"
},
"tac": {
"title": "Tracking Area Code",
"description": "Tracking Area Code in hexadecimal representation (range 0x0000 to 0xffff)",
"default": "0x0001",
"type": "string"
},
"root_sequence_index": {
"title": "Root Sequence Index",
"description": "Range: 0 to 837. Set the PRACH root sequence index (SIB2.rootSequenceIndex field). It must be different for each neighbour cell operating on the same frequency and sharing the same PRACH configuration.",
"type": "number",
"default": 204
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"enb_id": {
"title": "eNB ID",
"description": "eNB ID",
"type": "string",
"default": "0x1A2D0"
},
"gtp_addr": {
"title": "GTP Address",
"description": "String. Set the IP address (and optional port) on which the GTP-U packets are received. The default port is 2152. It is normally the IP address of the network interface connected to the core network.",
"type": "string",
"default": "127.0.1.1"
},
"mme_list": {
"title": "MME list",
"description": "Optionnal. List of MME to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"mme_addr": {
"title": "MME Address",
"description": "IP address (and optional port) of S1AP SCTP connection to the MME. The default port is 36412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the eNodeB, at most 6 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"attach_without_pdn": {
"default": false,
"title": "Attach Without PDN",
"description": "Optional boolean. Indicates if PLMN supports attach without PDN connectivity.",
"type": "boolean"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"lte_handover_a3_offset": {
"title": "A3 offset for LTE handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"lte_handover_time_to_trigger": {
"title": "Time to Trigger for LTE handover",
"description": "Time to triger after which LTE handover will be triggered if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 480
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"cell_id": {
"title": "Cell ID",
"description": "Concatenation of enb_id and cell_id of the neighbour cell",
"type": "string"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"enb_stats_fetch_period": {
"title": "eNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get eNB statistics",
"type": "number",
"default": 60
},
"enb_drb_stats_enabled": {
"title": "Enable eNB drb statistics",
"description": "Enable eNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"nr_bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "1 or 2. Number of DL antennas.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "1 or 2. Number of UL antennas.",
"type": "number",
"default": 2
},
"tdd_ul_dl_config": {
"title": "TDD",
"description": "TDD",
"type": "string",
"enum": [
"5ms 2UL 7DL 4/6 (default)",
"2.5ms 1UL 3DL 2/10",
"5ms 8UL 1DL 2/10 (maximum uplink)"
],
"default": "5ms 2UL 7DL 4/6 (default)"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"ssb_pos_bitmap": {
"title": "SSB Position Bitmap",
"description": "SSB position bitmap in bits (4, 8 or 64 bits depending on the DL frequency).",
"type": "string",
"default": 10000000
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID",
"type": "number",
"default": 500
},
"cell_id": {
"title": "Cell ID",
"description": "Cell ID",
"type": "string",
"default": "0x01"
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"gnb_id": {
"title": "gNB ID",
"description": "gNB ID",
"type": "string",
"default": "0x12345"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number",
"default": 28
},
"amf_list": {
"title": "AMF list",
"description": "Optionnal. List of AMF to which the gNodeB is connected",
"patternProperties": {
".*": {
"properties": {
"amf_addr": {
"title": "AMF Address",
"description": "IP address (and optional port) of NGAP SCTP connection to the AMF. The default port is 38412.",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"plmn_list": {
"title": "PLMN list",
"description": "List of PLMNs broadcasted by the gNodeB, at most 12 (default: 00101)",
"patternProperties": {
".*": {
"properties": {
"plmn": {
"default": "00101",
"title": "Public Land Mobile Network",
"description": "Public Land Mobile Network",
"type": "string"
},
"tac": {
"default": 100,
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
},
"ranac": {
"title": "Optional integer (range 0 to 255)",
"description": "RAN Area Code",
"type": "number"
},
"reserved": {
"default": false,
"title": "Reserved",
"description": "True if the cell is reserved for operator use.",
"type": "boolean"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nssai": {
"title": "AMF slices configuration",
"description": "AMF slices configuration.",
"patternProperties": {
".*": {
"properties": {
"sst": {
"default": 1,
"title": "Slice Service Type",
"description": "Integer (range 1 to 255).",
"type": "number"
},
"sd": {
"default": "0x000032",
"title": "Slice Differentiator",
"description": "Optional integer (range 0 to 0xFFFFFE)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"nr_handover_a3_offset": {
"title": "A3 offset for NR handover",
"description": "RSRP gain offset between gNBs which will trigger handover",
"type": "number",
"default": 6
},
"nr_handover_time_to_trigger": {
"title": "Time to Trigger for NR handover",
"description": "Time to triger after which NR handover will be triggerd if A3 offset is reached",
"type": "number",
"enum": [
0,
40,
64,
80,
100,
128,
160,
256,
320,
480,
512,
640,
1024,
1280,
2560,
5120
],
"default": 100
},
"ncell_list": {
"title": "Neighbour Cell Info",
"description": "Neighbour Cell Info",
"patternProperties": {
".*": {
"properties": {
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR Absolute Radio Frequency Channel Number of the neighbour cell",
"type": "number"
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID of the neighbour cell",
"type": "number"
},
"nr_cell_id": {
"title": "NR Cell ID",
"description": "Concatenation of gnb_id and cell_id of the neighbour cell",
"type": "string"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "number"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"xn_peers": {
"title": "XN Peers",
"description": "XN Peers",
"patternProperties": {
".*": {
"properties": {
"xn_addr": {
"title": "XN Address",
"description": "XN Address of the neighbour cell (gNB Address)",
"type": "string"
}
},
"type": "object"
}
},
"type": "object",
"default": {}
},
"websocket_password": {
"title": "Websocket password",
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"log_phy_debug": {
"title": "Physical layer log debug",
"description": "Enable debug mode for physical layer logs",
"type": "boolean",
"default": false
},
"gps_sync": {
"default": false,
"title": "GPS synchronisation",
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
"description": "Set to true to use IPv4 for AMF / MME addresses",
"type": "boolean"
},
"gnb_stats_fetch_period": {
"title": "gNB statistics fetch period (seconds)",
"description": "Describes how often a call to Amarisoft remote API is made to get gNB statistics",
"type": "number",
"default": 60
},
"gnb_drb_stats_enabled": {
"title": "Enable gNB drb statistics",
"description": "Enable gNB drb statistics through 100Hz polling, needed for E-UTRAN IP Throughput KPI",
"type": "boolean",
"default": true
},
"max_rx_sample_db": {
"title": "Maximum RX sample value (dB)",
"description": "Maximum RX sample threshold above which RX saturated promise will fail",
"type": "number",
"default": 0
},
"min_rxtx_delay": {
"title": "Minimum available time for radio front end processing (ms)",
"description": "Baseband latency promise will fail if minimum TX/RX diff reaches threshold (lower than this value)",
"type": "number",
"default": 0
},
"xlog_fluentbit_forward_host": {
"title": "Address to Forward Xlog by Fluenbit",
"description": "Address of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_port": {
"title": "Port to Forward Xlog by Fluentbit",
"description": "Optional Port of Remote Fluentd or Fluentbit Server to Forward Xlog",
"type": "string"
},
"xlog_fluentbit_forward_shared_key": {
"title": "Shared Key to Forward Xlog by Fluentbit",
"description": "Secret Key Shared with Remote Fluentd or Fluentbit Server for Authentication when Forwarding Xlog",
"type": "string"
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR ARFCN, you can retrieve from ENB/GNB side",
"type": "number"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": 40
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR ARFCN, you can retrieve from ENB/GNB side",
"type": "number"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": 2
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "001010123456789"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "{{ default_lte_bandwidth }}"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": {{ default_n_antenna_dl }}
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": {{ default_n_antenna_ul }}
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "{{ default_lte_imsi }}"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "{{ default_lte_k }}"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "number"
},
"band": {
"title": "NR band",
"description": "NR band number",
"type": "number"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number",
"default": {{ default_nr_bandwidth }}
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR ARFCN, you can retrieve from ENB/GNB side",
"type": "number"
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of DL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": {{ default_n_antenna_dl }}
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"description": "Enumeration: 1, 2, 4 or 8. Number of UL antennas. It must be the same for all NB-IoT and LTE cells sharing the same RF port.",
"type": "number",
"default": {{ default_n_antenna_ul }}
},
"imsi": {
"title": "IMSI",
"description": "IMSI",
"type": "string",
"default": "{{ default_nr_imsi }}"
},
"k": {
"title": "K",
"description": "Set the user secret key (as a 16 bytes hexadecimal string, or eventually 32 bytes hexadecimal string for TUAK).",
"type": "string",
"default": "{{ default_nr_k }}"
},
"sim_algo": {
"title": "sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm.",
"type": "string",
"default": "milenage"
},
"opc": {
"title": "opc",
"description": "Optional string. Operator key preprocessed with the user secret key (as a 16 byte hexadecimal string). When the Milenage authentication algorithm is used, either op or opc must be set.",
"type": "string",
"default": "milenage"
},
"amf": {
"title": "amf",
"description": "Range: 0 to 65535. Set the Authentication Management Field.",
"type": "string",
"default": "0x9001"
},
"sqn": {
"title": "sqn",
"description": "Optional String (6 byte hexadecimal string). Default = '000000000000'. Set the initial sequence number. For the XOR algorithm, the actual value does not matter. For the Milenage or TUAK algorithm, a sequence number resynchronization is initiated if the sequence number does not match the one stored in the USIM.",
"type": "string",
"default": "000000000000"
},
"impu": {
"title": "impu",
"description": "Array of string or object. Each string represent an IMPU and can be a sip URI or a telephone number.",
"type": "string",
"default": ""
},
"impi": {
"title": "impi",
"description": "String. Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
}
}
}
{
"$schema": "http://json-schema.org/draft-04/schema",
"description": "Values returned by UEsim instantiation (stub)",
"type": "object",
"properties": {}
}
{#- rat indicates with which mode ue is instantiated with - lte | nr #} # instance-ue implements UEsim service.
{%- set rat = slap_configuration['slap-software-type'] .removeprefix('ue-') %}
{%- do assert(rat in ('lte', 'nr'), rat) %}
[buildout] [buildout]
parts = parts =
directory directory
lte-ue-config lte-ue-config
lte-ue-service lte-ue-service
check-sdr-busy.py
monitor-base monitor-base
publish-connection-information publish-connection-information
...@@ -17,6 +14,21 @@ eggs-directory = {{ eggs_directory }} ...@@ -17,6 +14,21 @@ eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }} develop-eggs-directory = {{ develop_eggs_directory }}
offline = true offline = true
{%- set icell_kind='ue' %}
{%- import 'slaplte.jinja2' as slaplte with context %}
{%- import 'ru_libinstance.jinja2.cfg' as rulib with context %}
{%- set iue_dict = {} %}
{%- do slaplte.load_iue(iue_dict) %}
{%- do slaplte.check_loaded_everything() %}
{{ rulib.buildout() }}
[myslap]
# see instance-enb.jinja2.cfg about myslap
parameter_dict = {{ dumps(slapparameter_dict) }}
configuration = {{ dumps(slap_configuration) }}
[monitor-httpd-conf-parameter] [monitor-httpd-conf-parameter]
httpd-include-file = {{ buildout_directory }}/etc/httpd-include-file.conf httpd-include-file = {{ buildout_directory }}/etc/httpd-include-file.conf
port = ${monitor-instance-parameter:monitor-httpd-port} port = ${monitor-instance-parameter:monitor-httpd-port}
...@@ -31,23 +43,6 @@ minimum = 8035 ...@@ -31,23 +43,6 @@ minimum = 8035
maximum = 8055 maximum = 8055
ip = ${monitor-instance-parameter:monitor-httpd-ipv6} ip = ${monitor-instance-parameter:monitor-httpd-ipv6}
[slap-configuration]
recipe = slapos.cookbook:slapconfiguration.serialised
computer = {{ slap_connection['computer-id'] }}
partition = {{ slap_connection['partition-id'] }}
url = {{ slap_connection['server-url'] }}
key = {{ slap_connection['key-file'] }}
cert = {{ slap_connection['cert-file'] }}
configuration.default_lte_bandwidth = {{ default_lte_bandwidth }}
configuration.default_nr_bandwidth = {{ default_nr_bandwidth }}
configuration.default_n_antenna_dl = {{ default_n_antenna_dl }}
configuration.default_n_antenna_ul = {{ default_n_antenna_ul }}
configuration.default_lte_imsi = {{ default_lte_imsi }}
configuration.default_nr_imsi = {{ default_nr_imsi }}
configuration.default_lte_k = {{default_lte_k}}
configuration.default_nr_k = {{ default_nr_k }}
[directory] [directory]
recipe = slapos.cookbook:mkdirectory recipe = slapos.cookbook:mkdirectory
software = {{ buildout_directory }} software = {{ buildout_directory }}
...@@ -103,18 +98,15 @@ environment = ...@@ -103,18 +98,15 @@ environment =
[config-base] [config-base]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do extensions = jinja2.ext.do
extra-context =
context = context =
json ors false
section directory directory section directory directory
section slap_configuration slap-configuration
section pub_info publish-connection-information section pub_info publish-connection-information
key slapparameter_dict slap-configuration:configuration key slap_configuration myslap:configuration
{%- if rat == 'lte' %} key slapparameter_dict myslap:parameter_dict
json do_lte true import xbuildout xbuildout
json do_nr false ${:extra-context}
{%- elif rat == 'nr' %}
json do_lte false
json do_nr true
{%- endif %}
[lte-ue-config] [lte-ue-config]
<= config-base <= config-base
...@@ -124,12 +116,23 @@ url = ${ue-config-dl:target} ...@@ -124,12 +116,23 @@ url = ${ue-config-dl:target}
url = {{ ue_template }} url = {{ ue_template }}
{% endif %} {% endif %}
output = ${directory:etc}/ue.cfg output = ${directory:etc}/ue.cfg
import-list =
rawfile slaplte.jinja2 {{ slaplte_template }}
extra-context =
import json_module json
key iru_dict :iru_dict
key icell_dict :icell_dict
key iue_dict :iue_dict
iru_dict = {{ dumps(rulib.iru_dict) }}
icell_dict = {{ dumps(rulib.icell_dict) }}
iue_dict = {{ dumps(iue_dict) }}
[publish-connection-information] [publish-connection-information]
<= monitor-publish <= monitor-publish
recipe = slapos.cookbook:publish.serialised recipe = slapos.cookbook:publish.serialised
rue_bind_addr = ${slap-configuration:ipv6-random} rue_bind_addr = {{my_ipv6}}
com_addr = [${slap-configuration:ipv6-random}]:9002 com_addr = [{{my_ipv6}}]:9002
monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html
[monitor-instance-parameter] [monitor-instance-parameter]
...@@ -139,15 +142,3 @@ monitor-title = {{ slapparameter_dict['name'] | string }} ...@@ -139,15 +142,3 @@ monitor-title = {{ slapparameter_dict['name'] | string }}
{% if slapparameter_dict.get("monitor-password", None) %} {% if slapparameter_dict.get("monitor-password", None) %}
password = {{ slapparameter_dict['monitor-password'] | string }} password = {{ slapparameter_dict['monitor-password'] | string }}
{% endif %} {% endif %}
[macro.promise]
<= monitor-promise-base
name = ${:_buildout_section_name_}
[check-sdr-busy.py]
<= macro.promise
promise = check_sdr_busy
config-testing = {{ slapparameter_dict.get("testing", False) }}
config-sdr = {{ sdr }}
config-sdr_dev = 0
config-dma_chan = 0
...@@ -24,21 +24,23 @@ cert = $${slap-connection:cert-file} ...@@ -24,21 +24,23 @@ cert = $${slap-connection:cert-file}
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
output = $${buildout:directory}/$${:filename} output = $${buildout:directory}/$${:filename}
extra-context = extra-context =
depends = $${activate-eggs:recipe}
context = context =
import xbuildout xbuildout
import json_module json import json_module json
import netaddr netaddr import netaddr netaddr
import nrarfcn_module nrarfcn
import xearfcn_module xlte.earfcn
import xnrarfcn_module xlte.nrarfcn
key eggs_directory buildout:eggs-directory key eggs_directory buildout:eggs-directory
key develop_eggs_directory buildout:develop-eggs-directory key develop_eggs_directory buildout:develop-eggs-directory
raw buildout_directory ${buildout:directory} raw buildout_directory ${buildout:directory}
section directory directory
raw pythonwitheggs ${buildout:bin-directory}/pythonwitheggs raw pythonwitheggs ${buildout:bin-directory}/pythonwitheggs
section slap_connection slap-connection section slap_connection slap-connection
key slapparameter_dict slap-configuration:configuration key slapparameter_dict slap-configuration:configuration
key lan_ipv4 lan-ip:ipv4 key lan_ipv4 lan-ip:ipv4
raw rf_mode ${rf-mode:rf-mode} key my_ipv6 slap-configuration:ipv6-random
raw software_name ${rf-mode:software-name}
raw trx ${rf-mode:trx}
raw bbu ${rf-mode:bbu}
raw ru ${rf-mode:ru}
$${:extra-context} $${:extra-context}
import-list = import-list =
rawfile slaplte.jinja2 ${slaplte.jinja2:target} rawfile slaplte.jinja2 ${slaplte.jinja2:target}
...@@ -47,6 +49,33 @@ import-list = ...@@ -47,6 +49,33 @@ import-list =
rawfile ru_lopcomm_libinstance.jinja2.cfg ${ru_lopcomm_libinstance.jinja2.cfg:target} rawfile ru_lopcomm_libinstance.jinja2.cfg ${ru_lopcomm_libinstance.jinja2.cfg:target}
rawfile ru_sunwave_libinstance.jinja2.cfg ${ru_sunwave_libinstance.jinja2.cfg:target} rawfile ru_sunwave_libinstance.jinja2.cfg ${ru_sunwave_libinstance.jinja2.cfg:target}
# activate eggs and modules used in jinja2 templates
[activate-eggs]
recipe = slapos.recipe.build
init =
import pkg_resources as rpkg
buildout = self.buildout['buildout']
env = rpkg.Environment([buildout['develop-eggs-directory'],
buildout['eggs-directory']])
env.scan()
def activate(pkgspec):
req = rpkg.Requirement.parse(pkgspec)
for dist in rpkg.working_set.resolve([req], env):
rpkg.working_set.add(dist)
activate('xlte')
activate('nrarfcn')
# ~ import xbuildout
import sys, types
def readfile(path):
with open(path) as f:
return f.read()
xbuildout = types.ModuleType('xbuildout')
exec(readfile('${ru_xbuildout.py:target}'), xbuildout.__dict__)
assert 'xbuildout' not in sys.modules
sys.modules['xbuildout'] = xbuildout
[amarisoft] [amarisoft]
recipe = slapos.recipe.build recipe = slapos.recipe.build
...@@ -105,10 +134,8 @@ init = ...@@ -105,10 +134,8 @@ init =
[switch-softwaretype] [switch-softwaretype]
recipe = slapos.cookbook:switch-softwaretype recipe = slapos.cookbook:switch-softwaretype
enb = dynamic-template-enb:output enb = dynamic-template-enb:output
gnb = dynamic-template-enb:output
core-network = dynamic-template-core-network:output core-network = dynamic-template-core-network:output
ue-lte = dynamic-template-ue:output ue = dynamic-template-ue:output
ue-nr = dynamic-template-ue:output
RootSoftwareInstance = $${:core-network} RootSoftwareInstance = $${:core-network}
[dynamic-template-enb] [dynamic-template-enb]
...@@ -118,7 +145,6 @@ filename = instance-enb.cfg ...@@ -118,7 +145,6 @@ filename = instance-enb.cfg
extensions = jinja2.ext.do extensions = jinja2.ext.do
extra-context = extra-context =
raw monitor_template ${monitor2-template:output} raw monitor_template ${monitor2-template:output}
json RF {}
section comp_id comp-id section comp_id comp-id
section slap_configuration slap-configuration section slap_configuration slap-configuration
key lte_version amarisoft:lte-version key lte_version amarisoft:lte-version
...@@ -144,13 +170,6 @@ extra-context = ...@@ -144,13 +170,6 @@ extra-context =
raw ru_tapsplit ${ru_tapsplit:target} raw ru_tapsplit ${ru_tapsplit:target}
raw netcapdo ${netcapdo:exe} raw netcapdo ${netcapdo:exe}
raw openssl_location ${openssl:location} raw openssl_location ${openssl:location}
raw default_lte_bandwidth ${default-params:default-lte-bandwidth}
raw default_lte_inactivity_timer ${default-params:default-lte-inactivity-timer}
raw default_nr_bandwidth ${default-params:default-nr-bandwidth}
raw default_nr_ssb_pos_bitmap ${default-params:default-nr-ssb-pos-bitmap}
raw default_nr_inactivity_timer ${default-params:default-nr-inactivity-timer}
raw default_n_antenna_dl ${default-params:default-n-antenna-dl}
raw default_n_antenna_ul ${default-params:default-n-antenna-ul}
raw ru_dnsmasq_template ${ru_dnsmasq.jinja2.cfg:target} raw ru_dnsmasq_template ${ru_dnsmasq.jinja2.cfg:target}
raw dnsmasq_location ${dnsmasq:location} raw dnsmasq_location ${dnsmasq:location}
raw fluent_bit_location ${fluent-bit:location} raw fluent_bit_location ${fluent-bit:location}
...@@ -180,7 +199,7 @@ extra-context = ...@@ -180,7 +199,7 @@ extra-context =
[dynamic-template-ue] [dynamic-template-ue]
< = jinja2-template-base < = jinja2-template-base
url = ${template-ue:target} url = ${template-ue:target}
filename = instance-ue-lte.cfg filename = instance-ue.cfg
extensions = jinja2.ext.do extensions = jinja2.ext.do
extra-context = extra-context =
section slap_configuration slap-configuration section slap_configuration slap-configuration
...@@ -188,15 +207,26 @@ extra-context = ...@@ -188,15 +207,26 @@ extra-context =
key ue amarisoft:ue key ue amarisoft:ue
key sdr amarisoft:sdr key sdr amarisoft:sdr
raw ue_template ${ue.jinja2.cfg:target} raw ue_template ${ue.jinja2.cfg:target}
raw slaplte_template ${slaplte.jinja2:target}
raw openssl_location ${openssl:location} raw openssl_location ${openssl:location}
raw default_lte_bandwidth ${default-params:default-lte-bandwidth}
raw default_nr_bandwidth ${default-params:default-nr-bandwidth} raw ru_amarisoft_stats_template ${ru_amarisoft-stats.jinja2.py:target}
raw default_n_antenna_dl ${default-params:default-n-antenna-dl} raw ru_amarisoft_rf_info_template ${ru_amarisoft-rf-info.jinja2.py:target}
raw default_n_antenna_ul ${default-params:default-n-antenna-ul} raw ru_lopcomm_stats_template ${ru_lopcomm_stats.jinja2.py:target}
raw default_lte_imsi ${default-params:default-lte-imsi} raw ru_lopcomm_config_template ${ru_lopcomm_config.jinja2.py:target}
raw default_nr_imsi ${default-params:default-nr-imsi} raw ru_lopcomm_software_template ${ru_lopcomm_software.jinja2.py:target}
raw default_lte_k ${default-params:default-lte-k} raw ru_lopcomm_reset_info_template ${ru_lopcomm_reset-info.jinja2.py:target}
raw default_nr_k ${default-params:default-nr-k} raw ru_lopcomm_reset_template ${ru_lopcomm_reset.jinja2.py:target}
raw ru_lopcomm_CreateProcessingEle_template ${ru_lopcomm_CreateProcessingEle.jinja2.xml:target}
raw ru_lopcomm_cu_config_template ${ru_lopcomm_cu_config.jinja2.xml:target}
raw ru_lopcomm_firmware_path ${ru_lopcomm_firmware-dl:target}
raw ru_lopcomm_firmware_filename ${ru_lopcomm_firmware-dl:filename}
raw ru_tapsplit ${ru_tapsplit:target}
raw netcapdo ${netcapdo:exe}
raw ru_dnsmasq_template ${ru_dnsmasq.jinja2.cfg:target}
raw dnsmasq_location ${dnsmasq:location}
raw openssh_location ${openssh:location}
raw openssh_output_keygen ${openssh-output:keygen}
[ue-db-config] [ue-db-config]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
......
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer Cell. Common properties",
"type": "object",
"required": [
"cell_type",
"cell_kind",
"pci",
"tac"
],
"properties": {
"cell_type": {
"type": "string",
"options": { "hidden": true }
},
"cell_kind": {
"type": "string",
"const": "enb_peer",
"template": "enb_peer",
"options": { "hidden": true }
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer Cell",
"type": "object",
"oneOf": [
{ "$ref": "../../peer/cell/lte/input-schema.json" },
{ "$ref": "../../peer/cell/nr/input-schema.json" }
]
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "LTE Peer Cell",
"type": "object",
"required": [
"cell_type",
"cell_kind",
"pci",
"tac",
"e_cell_id",
"dl_earfcn"
],
"properties": {
"cell_type": {
"$ref": "../../../peer/cell/common.json#/properties/cell_type",
"const": "lte",
"template": "lte"
},
"e_cell_id": {
"title": "E-UTRAN Cell ID",
"description": "28 bit E-UTRAN cell identity. Concatenation of enb_id and cell_id of the neighbour cell.",
"type": "string"
},
"dl_earfcn": { "$ref": "../../../cell/lte/input-schema.json#/properties/dl_earfcn" },
"pci": { "$ref": "../../../cell/lte/input-schema.json#/properties/pci" },
"tac": { "$ref": "../../../cell/lte/input-schema.json#/properties/tac" }
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "NR Peer Cell",
"type": "object",
"required": [
"cell_type",
"cell_kind",
"pci",
"tac",
"nr_cell_id",
"gnb_id_bits",
"dl_nr_arfcn",
"nr_band"
],
"properties": {
"cell_type": {
"$ref": "../../../peer/cell/common.json#/properties/cell_type",
"const": "nr",
"template": "nr"
},
"nr_cell_id": {
"title": "NR Cell ID",
"description": "Concatenation of gnb_id and cell_id of the neighbour cell",
"type": "string"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "integer"
},
"dl_nr_arfcn": { "$ref": "../../../cell/nr/input-schema.json#/properties/dl_nr_arfcn" },
"nr_band": { "$ref": "../../../cell/nr/input-schema.json#/properties/nr_band" },
"ssb_nr_arfcn": { "$ref": "../../../cell/nr/input-schema.json#/properties/ssb_nr_arfcn" },
"ul_nr_arfcn": { "$ref": "../../../cell/nr/input-schema.json#/properties/ul_nr_arfcn" },
"pci": { "$ref": "../../../cell/nr/input-schema.json#/properties/pci" },
"tac": { "$ref": "../../../cell/nr/input-schema.json#/$defs/tac" }
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by Peer Cell instantiation (stub)",
"type": "object",
"properties": {}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer. Common properties",
"type": "object",
"required": [
"peer_type"
],
"properties": {
"peer_type": {
"type": "string",
"options": { "hidden": true }
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer eNB/gNB",
"type": "object",
"oneOf": [
{ "$ref": "../peer/lte/input-schema.json" },
{ "$ref": "../peer/nr/input-schema.json" }
]
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer eNB",
"type": "object",
"required": [
"peer_type",
"x2_addr"
],
"properties": {
"peer_type": {
"$ref": "../../peer/common.json#/properties/peer_type",
"const": "lte",
"template": "lte"
},
"x2_addr": {
"title": "X2 Address",
"description": "X2 Address of the neighbour node (eNB Address)",
"type": "string"
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer gNB",
"type": "object",
"required": [
"peer_type",
"xn_addr"
],
"properties": {
"peer_type": {
"$ref": "../../peer/common.json#/properties/peer_type",
"const": "nr",
"template": "nr"
},
"xn_addr": {
"title": "XN Address",
"description": "XN Address of the neighbour node (gNB Address)",
"type": "string"
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by Peer eNB/gNB instantiation (stub)",
"type": "object",
"properties": {}
}
#!/usr/bin/env python3
from jinja2 import Template
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--delete', action='store_true')
args = parser.parse_args()
if args.delete:
directory = os.path.dirname(os.path.realpath(__file__))
test_directory = os.path.join(directory, 'test')
for f in os.listdir(directory):
if 'tdd' in f or 'fdd' in f:
os.remove(os.path.join(directory, f))
for f in os.listdir(test_directory):
if 'testTDD' in f or 'testFDD' in f:
os.remove(os.path.join(test_directory, f))
exit()
global_context = {
'generated_file_message': "This file was generated using a jinja2 template and the render-templates script, don't modify directly."
}
software_list = [
{
'software_name' : 'tdd-ors',
'rf_mode' : 'tdd',
'trx' : 'sdr',
'bbu' : 'ors',
'ru' : 'ors',
}, {
'software_name' : 'fdd-ors',
'rf_mode' : 'fdd',
'trx' : 'sdr',
'bbu' : 'ors',
'ru' : 'ors',
}, {
'software_name' : 'tdd-m2ru',
'rf_mode' : 'tdd',
'trx' : 'cpri',
'bbu' : 'server',
'ru' : 'm2ru',
}, {
'software_name' : 'fdd-lopcomm',
'rf_mode' : 'fdd',
'trx' : 'cpri',
'bbu' : 'server',
'ru' : 'lopcomm',
}, {
'software_name' : 'fdd',
'rf_mode' : 'fdd',
'trx' : 'sdr',
'bbu' : 'server',
'ru' : 'any',
}, {
'software_name' : 'tdd',
'rf_mode' : 'tdd',
'trx' : 'sdr',
'bbu' : 'server',
'ru' : 'any',
}
]
for i in range (len(software_list)):
software_list[i].update({
'default_lte_bandwidth' : "20 MHz",
'default_lte_imsi' : "001010123456789",
'default_lte_k' : "00112233445566778899aabbccddeeff",
'default_lte_inactivity_timer' : 10000,
'default_nr_bandwidth' : 40,
'default_nr_imsi' : "001010123456789",
'default_nr_k' : "00112233445566778899aabbccddeeff",
'default_nr_ssb_pos_bitmap' : "10000000",
'default_n_antenna_dl' : 2,
'default_n_antenna_ul' : 2,
'default_nr_inactivity_timer' : 10000,
})
with open('software.cfg.json.jinja2', 'r') as f:
software_json_template = Template(f.read())
instance_json_template_map = {}
for software_type in ['enb', 'gnb', 'ue-lte', 'ue-nr']:
with open('instance-{}-input-schema.json.jinja2'.format(software_type), 'r') as f:
instance_json_template_map[software_type] = Template(f.read())
with open('software.jinja2.cfg', 'r') as f:
software_template = Template(f.read())
with open('test/test.jinja2.py', 'r') as f:
test_template = Template(f.read())
for software in software_list:
with open('software-{}.cfg.json'.format(software['software_name']),
'w+') as f:
f.write(software_json_template.render(**software, **global_context) + '\n')
with open('test/test{}.py'.format(software['software_name'].upper()),
'w+') as f:
f.write(test_template.render(**software, **global_context) + '\n')
with open('software-{}.cfg'.format(software['software_name']),
'w+') as f:
f.write(software_template.render(**software, **global_context) + '\n')
for software_type in ['enb', 'gnb', 'ue-lte', 'ue-nr']:
with open('instance-{}-{}-input-schema.json'.format(
software['software_name'],
software_type),
'w+') as f:
f.write(instance_json_template_map[software_type].render(**software, **global_context) + '\n')
...@@ -40,12 +40,11 @@ class enbWebSocket: ...@@ -40,12 +40,11 @@ class enbWebSocket:
def stats(self): def stats(self):
if {{ testing }}: if {{ testing }}:
from random import randint from random import randint
nrx = {{ iru_dict.values() | sum(attribute='_.n_antenna_ul') }}
rxv = [{'sat': 0, 'max': randint(-500,-100) / 10.0} for _ in range(nrx)]
r = { r = {
'message': 'stats', 'message': 'stats',
'samples': {'rx': [ 'samples': {'rx': rxv}
{'sat': 0, 'max': randint(-500,-100) / 10.0},
{'sat': 0, 'max': randint(-500,-100) / 10.0},
]}
} }
else: else:
self.send({ self.send({
......
...@@ -39,3 +39,6 @@ exe = ${netcapdo:exe} ...@@ -39,3 +39,6 @@ exe = ${netcapdo:exe}
[ru_amarisoft-rf-info.jinja2.py] [ru_amarisoft-rf-info.jinja2.py]
<= download-base <= download-base
[ru_xbuildout.py]
<= download-base
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Radio Unit. Common properties",
"type": "object",
"required": [
"ru_type",
"ru_link_type",
"n_antenna_dl",
"n_antenna_ul",
"tx_gain",
"rx_gain"
],
"properties": {
"ru_type": {
"type": "string",
"options": { "hidden": true }
},
"ru_link_type": {
"type": "string",
"options": { "hidden": true }
},
"n_antenna_dl": {
"title": "Number of DL antennas",
"type": "integer"
},
"n_antenna_ul": {
"title": "Number of UL antennas",
"type": "integer"
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"type": "number"
},
"txrx_active": {
"title": "Activate Tx/Rx",
"description": "Activate or inactivate Tx transmission and Rx reception. When inactive RU does no radio.",
"type": "string",
"enum": ["ACTIVE", "INACTIVE"],
"default": "INACTIVE"
},
"cpri_link": {
"title": "CPRI link settings",
"options": {
"dependencies": {
"ru_link_type": "cpri"
}
},
"type": "object",
"required": [
"sdr_dev",
"sfp_port",
"mapping"
],
"properties": {
"sdr_dev": {
"title": "/dev/sdr # of CPRI board",
"type": "integer"
},
"sfp_port": {
"title": "SFP port # on the CPRI board",
"type": "integer"
},
"mapping": {
"title": "Mapping method of AxCs on the CPRI",
"type": "string",
"enum": ["standard", "hw", "spread", "bf1"]
},
"mult": {
"title": "CPRI line bit rate multipler",
"description": "Select the CPRI line bit rate in terms of multiple of option 1 (614.4 Mbps). E.g set 4 for option 3, 8 for option 5 and 16 for option 7",
"type": "integer",
"enum": [4, 5, 8, 16],
"default": 16
},
"rx_delay": {
"title": "CPRI RX Delay",
"description": "Delays between TX and RX position in CPRI frame. This should be set to the value of (T2a + T3a - Toffset) provided by the RU specification.",
"type": "number",
"default": 0
},
"tx_delay": {
"title": "CPRI TX Delay",
"description": "Advances Start of Frame relative to PPS to compensate for delays in transmit line and RU. This should be set to T12 + T2a.",
"type": "number",
"default": 0
},
"tx_dbm": {
"title": "CPRI TX dBm",
"description": "Optional floating points value in dBm (default 0). Needed by ENB/GNB to have a notion of actual output power. Computed from maximum power output of the RRH for a 0dBFS input signal (full scale). ",
"type": "number",
"default": 0
}
}
},
"mac_addr": {
"title": "RU MAC address",
"description": "RU MAC address used for NETCONF",
"type": "string",
"options": {
"dependencies": {
"ru_link_type": "cpri"
}
}
}
}
}
{%- set B = xbuildout.encode -%}
dhcp-leasefile={{ directory['etc'] }}/dnsmasq.leases dhcp-leasefile={{ directory['etc'] }}/dnsmasq.leases
port=5354 port=5354
{%- for (cell_ref, cell) in cell_list|dictsort | selectattr('1._tap', 'defined') %} {%- for (ru_ref, iru) in iru_dict|dictsort | selectattr('1._.cpri_link', 'defined') %}
{%- set ru_tap = cell._tap %} {%- set ru = iru['_'] %}
{%- 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 %}
# {{ cell_ref }} @ {{ ru_tap }} # {{ B(ru_ref) }} @ {{ ru_tap }}
{#- TODO consider using /128 as we give only 1 address to RU #} {#- TODO consider using /128 as we give only 1 address to RU #}
dhcp-range=tag:{{ ru_tap }},{{ vtap.gateway }},{{ vtap.gateway }},static,{{ max(plen,64) }},5m dhcp-range=tag:{{ ru_tap }},{{ vtap.gateway }},{{ vtap.gateway }},static,{{ max(plen,64) }},5m
dhcp-host={{ cell.ru_mac_addr }},tag:{{ ru_tap }},[{{ vtap.gateway }}] dhcp-host={{ ru.mac_addr }},tag:{{ ru_tap }},[{{ vtap.gateway }}]
# option 17 used for RU callhome # option 17 used for RU callhome
# dhcp-option=option6:17,[{{ vtap.addr }}] # dhcp-option=option6:17,[{{ vtap.addr }}]
{%- endfor %} {%- endfor %}
......
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Radio Unit",
"type": "object",
"oneOf": [
{ "$ref": "sdr/input-schema.json" },
{ "$ref": "lopcomm/input-schema.json" },
{ "$ref": "sunwave/input-schema.json" }
]
}
{#- Package ru/libinstance provides common instance code for handling Radio Units and cells. {#- Package ru/libinstance provides common instance code for handling Radio Units and cells.
Use buildout() macro to emit instance-level code to Set global icell_kind=enb|ue before importing to indicate which kind of
handle configured RUs. cells (server- or client-level) need to be configured. Then, after
importing, use buildout() macro to emit instance-level code to
handle configured RUs and cells.
NOTE: before importing package slaplte.jinja2 needs to already loaded as NOTE: before importing package slaplte.jinja2 needs to be already loaded as
{%- 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() .
#} #}
{#- cell_list keeps cell registry #} {#- iru_dict and icell_dict keep RU and cell registries
{%- set cell_list = {} %} iru_dict: reference -> iru
{%- do slaplte.load_cell(cell_list) %} icell_dict: reference -> icell
#}
{%- set iru_dict = {} %}
{%- set icell_dict = {} %}
{%- do slaplte.load_iru_and_icell(iru_dict, icell_dict, icell_kind) %}
{%- macro buildout() %} {%- macro buildout() %}
{%- set root = slap_configuration['instance-title'] %}
{%- set testing = slapparameter_dict.get("testing", False) %} {%- set testing = slapparameter_dict.get("testing", False) %}
{#- B(name) returns buildout-encoded form of name #}
{%- set B = xbuildout.encode %}
{#- part emits new buildout section and registers it into buildout.parts #} {#- part emits new buildout section and registers it into buildout.parts #}
{%- set parts_list = [] %} {%- set parts_list = [] %}
{%- macro part(name) %} {%- macro part(name) %}
{%- do parts_list.append(name) %} {%- do parts_list.append(B(name)) %}
[{{ name }}] [{{ B(name) }}]
{%- endmacro %} {%- endmacro %}
{#- 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 = {{ dumps('%s.py' % pretty_name) }}
output = {{ dumps('%s/plugin/%s.py' % (directory.etc, pretty_name)) }}
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 %}
...@@ -43,14 +60,14 @@ config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }} ...@@ -43,14 +60,14 @@ config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
sunwave=rudrv_sunwave) %} sunwave=rudrv_sunwave) %}
{%- set rudrv_init = {} %} {%- set rudrv_init = {} %}
{#- split slapos tap interface for each RU {#- split slapos tap interface for each RU that needs its own tap.
fallback to non-split approach for ntap <= 1 to avoid hard-dependecy on setcap/tapsplit fallback to non-split approach for ntap <= 1 to avoid hard-dependency on setcap/tapsplit
TODO Relying on setcap and tapsplit should be removed once SlapOS is improved to TODO Relying on setcap and tapsplit should be removed once SlapOS is improved to
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(cell_list|dictsort)) %} {%- 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
...@@ -132,7 +149,7 @@ init = ...@@ -132,7 +149,7 @@ init =
{#- provide CPRI-based RUs IP address via DHCP #} {#- provide CPRI-based RUs IP address via DHCP #}
{%- if trx == 'cpri' %} {%- if ntap > 0 %}
[dnsmasq-config] [dnsmasq-config]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
url = {{ru_dnsmasq_template}} url = {{ru_dnsmasq_template}}
...@@ -140,16 +157,16 @@ filename = dnsmasq.cfg ...@@ -140,16 +157,16 @@ filename = dnsmasq.cfg
extensions = jinja2.ext.do extensions = jinja2.ext.do
output = ${directory:etc}/${:filename} output = ${directory:etc}/${:filename}
context = context =
import xbuildout xbuildout
import json_module json import json_module json
import netaddr netaddr import netaddr netaddr
section directory directory section directory directory
section vtap_jdict vtap_jdict section vtap_jdict vtap_jdict
json cell_list {{ cell_list | tojson }} key iru_dict :iru_dict
iru_dict = {{ dumps(iru_dict) }}
{{ part('dnsmasq-service') }} {{ part('dnsmasq-service') }}
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
port = 5353
ip = ${slap-configuration:tun-ipv4-addr}
command-line = {{ dnsmasq_location }}/sbin/dnsmasq --conf-file=${dnsmasq-config:output} -x ${directory:run}/dnsmasq.pid --local-service --keep-in-foreground command-line = {{ dnsmasq_location }}/sbin/dnsmasq --conf-file=${dnsmasq-config:output} -x ${directory:run}/dnsmasq.pid --local-service --keep-in-foreground
wrapper-path = ${directory:service}/dnsmasq wrapper-path = ${directory:service}/dnsmasq
mode = 0775 mode = 0775
...@@ -158,38 +175,45 @@ hash-files = ...@@ -158,38 +175,45 @@ hash-files =
# {# promise('dnsmasq-listen') #} # {# promise('dnsmasq-listen') #}
#promise = check_socket_listening #promise = check_socket_listening
#config-host = ${dnsmasq-service:ip} #config-host = ...
#config-port = ${dnsmasq-service:port} #config-port = ...
{%- endif %} {%- endif %}
{#- 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 #}
{%- set ru_type = {'lopcomm': 'lopcomm', 'm2ru': 'sunwave'}.get(ru, 'sdr') %} {%- for ru_ref, iru in iru_dict|dictsort %}
{%- set rudrv = rudrv_dict[ru_type] %} {%- set ru = iru['_'] %}
{%- for i, (cell_ref, cell) in enumerate(cell_list|dictsort) %}
{%- set ru_ref = cell_ref if cell_ref != 'default' else 'RU' %} {#- cells that are using iru #}
{%- set n_antenna_ul = int(slapparameter_dict.get('n_antenna_ul', default_n_antenna_ul)) %} {%- set iru_icell_list = [] %}
{%- for cell_ref, icell in icell_dict|dictsort %}
# {{ ru_ref }} ({{ ru_type}}) {%- if ru_ref == J(jcell_ru_ref(icell, icell_dict)) %}
{%- if trx == 'sdr' %} {%- do iru_icell_list.append(icell) %}
{{ promise('%s-sdr-busy' % ru_ref) }} {%- endif %}
{%- endfor %}
# {{ dumps(ru_ref) }} {{ ru.n_antenna_dl }}T{{ ru.n_antenna_ul }}R ({{ ru.ru_type }})
{%- if ru.ru_link_type == 'sdr' %}
{%- for (i, n) in enumerate(ru.sdr_dev_list) %}
{{ promise('%s-sdr-busy%s' % (ru_ref, '-%d' % (i+1) if i > 0 else '')) }}
promise = check_sdr_busy promise = check_sdr_busy
config-sdr = {{ sdr }} config-sdr = {{ sdr }}
config-sdr_dev = 0 config-sdr_dev = {{ n }}
config-dma_chan = 0 config-dma_chan = 0
{%- endfor %}
{%- elif trx == 'cpri' %} {%- elif ru.ru_link_type == 'cpri' %}
{{ promise('%s-sdr-busy' % ru_ref) }} {{ promise('%s-sdr-busy' % ru_ref) }}
promise = check_sdr_busy promise = check_sdr_busy
config-sdr = {{ sdr }} config-sdr = {{ sdr }}
config-sdr_dev = {{ slapparameter_dict.get('sdr_number', 0) }} config-sdr_dev = {{ ru.cpri_link.sdr_dev }}
config-dma_chan = {{ cell.cpri_port_number }} config-dma_chan = {{ ru.cpri_link.sfp_port }}
{{ promise('%s-cpri-lock' % ru_ref) }} {{ promise('%s-cpri-lock' % ru_ref) }}
promise = check_cpri_lock promise = check_cpri_lock
config-sdr_dev = {{ slapparameter_dict.get('sdr_number', 0) }} config-sdr_dev = {{ ru.cpri_link.sdr_dev }}
config-sfp_port = {{ cell.cpri_port_number }} config-sfp_port = {{ ru.cpri_link.sfp_port }}
config-amarisoft-rf-info-log = ${ru_amarisoft-rf-info-template:log-output} config-amarisoft-rf-info-log = ${ru_amarisoft-rf-info-template:log-output}
{%- else %} {%- else %}
...@@ -198,16 +222,99 @@ config-amarisoft-rf-info-log = ${ru_amarisoft-rf-info-template:log-output} ...@@ -198,16 +222,99 @@ config-amarisoft-rf-info-log = ${ru_amarisoft-rf-info-template:log-output}
{{ promise('%s-rx-saturated' % ru_ref) }} {{ promise('%s-rx-saturated' % ru_ref) }}
promise = check_rx_saturated promise = check_rx_saturated
config-rf-rx-chan-list = {{ list(range(i*n_antenna_ul, (i+1)*n_antenna_ul)) }} config-rf-rx-chan-list = {{ list(range(ru._rf_chan_rx, ru._rf_chan_rx + ru.n_antenna_ul)) }}
config-amarisoft-stats-log = ${ru_amarisoft-stats-template:log-output} config-amarisoft-stats-log = ${ru_amarisoft-stats-template:log-output}
config-max-rx-sample-db = {{ slapparameter_dict.get("max_rx_sample_db", 0) }} config-max-rx-sample-db = {{ slapparameter_dict.get("max_rx_sample_db", 0) }}
{#- driver-specific part #} {#- driver-specific part #}
{%- if not rudrv_init.get(ru_type) %} {%- set rudrv = rudrv_dict[ru.ru_type] %}
{%- if not rudrv_init.get(ru.ru_type) %}
{{ rudrv.buildout() }} {{ rudrv.buildout() }}
{%- do rudrv_init.update({ru_type: 1}) %} {%- do rudrv_init.update({ru.ru_type: 1}) %}
{%- endif %}
{{ rudrv.buildout_iru(iru, iru_icell_list) }}
{#- publish information about RU (skipping synthetic) #}
{%- if iru.slave_reference %}
{{ part('ipublish-%s' % ru_ref) }}
recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ dumps(iru.slave_reference) }}
{{ slap_configuration['slap-software-type'] }} = {{ dumps(root) }}
{%- set iru_icell_ref_list = [] %}
{%- for icell in iru_icell_list %}
{%- do iru_icell_ref_list.append(J(jref_of_shared(icell))) %}
{%- endfor %}
cell-list = {{ dumps(iru_icell_ref_list) }}
{%- if ru.ru_link_type == 'cpri' %}
ipv6 = ${vtap.{{ ru.cpri_link._tap }}:gateway}
{%- endif %} {%- endif %}
{{ rudrv.buildout_ru(ru_ref, cell) }} tx_gain = {{ dumps(ru.tx_gain) }}
rx_gain = {{ dumps(ru.rx_gain) }}
txrx_active = {{ dumps(ru.txrx_active) }}
{%- endif %}
{%- endfor %}
{#- handle configured cells #}
{%- for cell_ref, icell in icell_dict|dictsort %}
{%- set cell = icell['_'] %}
{%- set ru_ref = J(jcell_ru_ref(icell, icell_dict)) %}
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
{%- if icell_kind == 'enb' %}
{#- generate CELL-drb.cfg and CELL-sib23.asn #}
{{ part('drb-config-%s' % cell_ref) }}
<= config-base
url = {{ {'lte': drb_lte_template, 'nr': drb_nr_template} [cell.cell_type] }}
output = ${directory:etc}/{{B('%s-drb.cfg' % cell_ref)}}
extra-context =
key cell_ref :cell_ref
key cell :cell
key ru_ref :ru_ref
key ru :ru
cell_ref = {{ dumps(cell_ref) }}
cell = {{ dumps(cell ) }}
ru_ref = {{ dumps(ru_ref ) }}
ru = {{ dumps(ru ) }}
{{ part('sib23-config-%s' % cell_ref) }}
<= config-base
url = {{ sib23_template }}
output = ${directory:etc}/{{B('%s-sib23.asn' % cell_ref)}}
extra-context =
key cell_ref :cell_ref
key cell :cell
key ru_ref :ru_ref
key ru :ru
cell_ref = {{ dumps(cell_ref) }}
cell = {{ dumps(cell ) }}
ru_ref = {{ dumps(ru_ref ) }}
ru = {{ dumps(ru ) }}
{%- endif %}
{#- publish information about the cell (skipping synthetic) #}
{%- if icell.slave_reference %}
{{ part('ipublish-%s' % cell_ref) }}
recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ dumps(icell.slave_reference) }}
{{ slap_configuration['slap-software-type'] }} = {{ dumps(root) }}
ru = {{ dumps(ru_ref) }}
{%- if cell.cell_type == 'lte' %}
band = {{ dumps('b%d' % xearfcn_module.band(cell.dl_earfcn)[0].band) }}
dl_earfcn = {{ dumps(cell.dl_earfcn) }}
ul_earfcn = {{ dumps(cell.ul_earfcn) }}
{%- elif cell.cell_type == 'nr' %}
band = {{ dumps('n%d' % cell.nr_band) }}
dl_nr_arfcn = {{ dumps(cell.dl_nr_arfcn) }}
ul_nr_arfcn = {{ dumps(cell.ul_nr_arfcn) }}
ssb_nr_arfcn= {{ dumps(cell.ssb_nr_arfcn) }}
{%- else %}
{%- do bug('unreachable') %}
{%- 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
...@@ -219,7 +326,7 @@ extensions = jinja2.ext.do ...@@ -219,7 +326,7 @@ extensions = jinja2.ext.do
log-output = ${directory:var}/log/amarisoft-rf-info.json.log log-output = ${directory:var}/log/amarisoft-rf-info.json.log
context = context =
section directory directory section directory directory
key slapparameter_dict slap-configuration:configuration key slapparameter_dict myslap:parameter_dict
key log_file :log-output key log_file :log-output
raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }} raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
raw testing {{ testing }} raw testing {{ testing }}
...@@ -242,11 +349,13 @@ extensions = jinja2.ext.do ...@@ -242,11 +349,13 @@ extensions = jinja2.ext.do
log-output = ${directory:var}/log/amarisoft-stats.json.log log-output = ${directory:var}/log/amarisoft-stats.json.log
context = context =
section directory directory section directory directory
key slapparameter_dict slap-configuration:configuration key slapparameter_dict myslap:parameter_dict
key log_file :log-output key log_file :log-output
raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }} raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
raw testing {{ testing }} raw testing {{ testing }}
raw python_path {{ buildout_directory}}/bin/pythonwitheggs raw python_path {{ buildout_directory}}/bin/pythonwitheggs
key iru_dict :iru_dict
iru_dict = {{ dumps(iru_dict) }}
mode = 0775 mode = 0775
url = {{ ru_amarisoft_stats_template }} url = {{ ru_amarisoft_stats_template }}
output = ${directory:bin}/amarisoft-stats.py output = ${directory:bin}/amarisoft-stats.py
......
<xc:config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0"> <xc:config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
{%- set n_antenna_dl = slapparameter_dict.get('n_antenna_dl', int(slap_configuration['configuration.default_n_antenna_dl'])) %}
{%- set n_antenna_ul = slapparameter_dict.get('n_antenna_ul', int(slap_configuration['configuration.default_n_antenna_ul'])) %}
<user-plane-configuration xc:operation="replace" xmlns="urn:o-ran:uplane-conf-option8:1.0"> <user-plane-configuration xc:operation="replace" xmlns="urn:o-ran:uplane-conf-option8:1.0">
<!-- TX path: eaxcid → TxEndpoint <!-- TX path: eaxcid → TxEndpoint
...@@ -11,7 +9,7 @@ ...@@ -11,7 +9,7 @@
(static TxEndpoint, TxArray and their association are defined by RU itself) (static TxEndpoint, TxArray and their association are defined by RU itself)
--> -->
{%- set TxCarrier = 'TXA0CC00' %} {%- set TxCarrier = 'TXA0CC00' %}
{%- for ant in range(n_antenna_dl) %} {%- for ant in range(ru.n_antenna_dl) %}
{%- set port = ant // 2 %} {%- set port = ant // 2 %}
{%- set chan = ant % 2 %} {%- set chan = ant % 2 %}
{%- set txep = 'TXA0P%02dC%02d' % (port, chan) %} {%- set txep = 'TXA0P%02dC%02d' % (port, chan) %}
...@@ -47,7 +45,7 @@ ...@@ -47,7 +45,7 @@
(static RxEndpoint, RxArray and their association are defined by RU itself) (static RxEndpoint, RxArray and their association are defined by RU itself)
--> -->
{%- set RxCarrier = 'RXA0CC00' %} {%- set RxCarrier = 'RXA0CC00' %}
{%- for ant in range(n_antenna_ul) %} {%- for ant in range(ru.n_antenna_ul) %}
{%- set port = ant // 2 %} {%- set port = ant // 2 %}
{%- set chan = ant % 2 %} {%- set chan = ant % 2 %}
{%- set rxep = 'RXA0P%02dC%02d' % (port, chan) %} {%- set rxep = 'RXA0P%02dC%02d' % (port, chan) %}
...@@ -90,26 +88,43 @@ ...@@ -90,26 +88,43 @@
<!-- TX/RX carriers --> <!-- TX/RX carriers -->
<!-- TODO support multiple cells over 1 RU -->
{%- if cell.cell_type == 'lte' %}
{%- set dl_arfcn = cell.dl_earfcn %}
{%- set ul_arfcn = cell.ul_earfcn %}
{%- set dl_freq = int(xearfcn_module.frequency(dl_arfcn) * 1e6) %}
{%- set ul_freq = int(xearfcn_module.frequency(ul_arfcn) * 1e6) %}
{%- elif cell.cell_type == 'nr' %}
{%- set dl_arfcn = cell.dl_nr_arfcn %}
{%- set ul_arfcn = cell.ul_nr_arfcn %}
{%- set dl_freq = int(xnrarfcn_module.frequency(dl_arfcn) * 1e6) %}
{%- set ul_freq = int(xnrarfcn_module.frequency(ul_arfcn) * 1e6) %}
{%- else %}
{%- do bug('unreachable') %}
{%- endif %}
{%- set bw = int(cell.bandwidth * 1e6) %}
<tx-array-carriers> <tx-array-carriers>
<name>{{ TxCarrier }}</name> <name>{{ TxCarrier }}</name>
<absolute-frequency-center>{{ slapparameter_dict.get('dl_earfcn', 300) }}</absolute-frequency-center> <absolute-frequency-center>{{ dl_arfcn }}</absolute-frequency-center>
<center-of-channel-bandwidth>{{ 1000000*slapparameter_dict.get('txa0cc00_center_frequency', 2140) }}</center-of-channel-bandwidth> <center-of-channel-bandwidth>{{ dl_freq }}</center-of-channel-bandwidth>
<channel-bandwidth>{{ {'1.4 MHz': 1400000, '3 MHz': 3000000, '5 MHz': 5000000, '10 MHz': 10000000, '15 MHz': 15000000, '20 MHz': 20000000}.get(slapparameter_dict.get('bandwidth'), '20 MHz') }}</channel-bandwidth> <channel-bandwidth>{{ bw }}</channel-bandwidth>
<active>{{ slapparameter_dict.get('txa0cc00_active', 'INACTIVE') }}</active> <active>{{ ru.txrx_active }}</active>
<rw-type>LTE</rw-type> <rw-type>{{ cell.cell_type | upper }}</rw-type>
<rw-duplex-scheme>FDD</rw-duplex-scheme> <rw-duplex-scheme>{{ cell.rf_mode | upper }}</rw-duplex-scheme>
<gain>{{ slapparameter_dict.get('txa0cc00_gain', '-20') }}</gain> <gain>{{ ru.tx_gain }}</gain>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset> <downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset> <downlink-sfn-offset>0</downlink-sfn-offset>
</tx-array-carriers> </tx-array-carriers>
<rx-array-carriers> <rx-array-carriers>
<name>{{ RxCarrier }}</name> <name>{{ RxCarrier }}</name>
<absolute-frequency-center>{{ slapparameter_dict.get('rxa0cc00_center_frequency_earfcn', 18300) }}</absolute-frequency-center> <absolute-frequency-center>{{ ul_arfcn }}</absolute-frequency-center>
<center-of-channel-bandwidth>{{ 1000000*slapparameter_dict.get('rxa0cc00_center_frequency', 1950) }}</center-of-channel-bandwidth> <center-of-channel-bandwidth>{{ ul_freq }}</center-of-channel-bandwidth>
<channel-bandwidth>{{ {'1.4 MHz': 1400000, '3 MHz': 3000000, '5 MHz': 5000000, '10 MHz': 10000000, '15 MHz': 15000000, '20 MHz': 20000000}.get(slapparameter_dict.get('bandwidth'), '20 MHz') }}</channel-bandwidth> <channel-bandwidth>{{ bw }}</channel-bandwidth>
<active>{{ slapparameter_dict.get('rxa0cc00_active', 'INACTIVE') }}</active> <active>{{ ru.txrx_active }}</active>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset> <downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset> <downlink-sfn-offset>0</downlink-sfn-offset>
<!-- <gain>{{ ru.rx_gain }}</gain> -->
<!-- TODO(lu.xu): clarify with Lopcomm regaring rx gain -->
<gain-correction>0.0</gain-correction> <gain-correction>0.0</gain-correction>
<n-ta-offset>0</n-ta-offset> <n-ta-offset>0</n-ta-offset>
</rx-array-carriers> </rx-array-carriers>
......
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Lopcomm ORAN",
"type": "object",
"required": [
"ru_type",
"ru_link_type",
"n_antenna_dl",
"n_antenna_ul",
"tx_gain",
"rx_gain",
"cpri_link",
"mac_addr"
],
"properties": {
"$ref": "../../ru/common.json#/properties",
"ru_type": {
"$ref": "#/properties/ru_type",
"const": "lopcomm",
"template": "lopcomm"
},
"ru_link_type": {
"$ref": "#/properties/ru_link_type",
"const": "cpri",
"template": "cpri"
},
"n_antenna_dl": {
"$ref": "#/properties/n_antenna_dl",
"default": 2
},
"n_antenna_ul": {
"$ref": "#/properties/n_antenna_ul",
"default": 2
},
"cpri_link": {
"$ref": "#/properties/cpri_link",
"properties": {
"$ref": "#/properties/cpri_link/properties",
"mapping": {
"$ref": "#/properties/cpri_link/properties/mapping",
"const": "hw",
"enum": ["hw"],
"options": { "hidden": true }
},
"rx_delay": {
"$ref": "#/properties/cpri_link/properties/rx_delay",
"default": 25.11
},
"tx_delay": {
"$ref": "#/properties/cpri_link/properties/tx_delay",
"default": 14.71
},
"tx_dbm": {
"$ref": "#/properties/cpri_link/properties/tx_dbm",
"default": 63
}
}
},
"reset_schedule": {
"title": "Cron schedule for RRH reset",
"description": "Refer https://crontab.guru/ to make a reset schedule for RRH, for example, '0 1 * * *' means the RRH will reset every day at 1 am",
"type": "string"
}
}
}
{#- 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, 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 #}
{%- if not testing %} {%- if not testing %}
{{ promise('%s-netconf-socket' % ru_ref) }} {{ promise('%s-netconf-socket' % ru_ref) }}
promise = check_socket_listening promise = check_socket_listening
config-host = ${vtap.{{cell._tap}}:gateway} config-host = ${vtap.{{ru.cpri_link._tap}}:gateway}
config-port = 830 config-port = 830
{%- endif %} {%- endif %}
{#- push firmware to RU #} {#- push firmware to RU #}
[{{ru_ref}}-software-template] {{ part('%s-software-template' % ru_ref) }}
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-software _logbase = ${directory:var}/log/{{B('%s-software' % ru_ref)}}
log-output = ${:_logbase}.log log-output = ${:_logbase}.log
software-reply-json-log-output = ${:_logbase}-reply.json.log software-reply-json-log-output = ${:_logbase}-reply.json.log
remote-file-path = sftp://${user-info:pw-name}@[${sshd-service:ipv6}]:${sshd-service:port}{{ru_lopcomm_firmware_path}} remote-file-path = sftp://${user-info:pw-name}@[${sshd-service:ipv6}]:${sshd-service:port}{{ru_lopcomm_firmware_path}}
is_firmware_updated = ${directory:etc}/{{ru_ref}}.is_firmware_updated is_firmware_updated = ${directory:etc}/{{B('%s.is_firmware_updated' % ru_ref)}}
context = context =
section directory directory section directory directory
section vtap vtap.{{ cell._tap }} section vtap vtap.{{ ru.cpri_link._tap }}
key slapparameter_dict slap-configuration:configuration key slapparameter_dict myslap:parameter_dict
key log_file :log-output key log_file :log-output
key software_reply_json_log_file :software-reply-json-log-output key software_reply_json_log_file :software-reply-json-log-output
key remote_file_path :remote-file-path key remote_file_path :remote-file-path
...@@ -37,63 +45,70 @@ context = ...@@ -37,63 +45,70 @@ context =
import netaddr netaddr import netaddr netaddr
mode = 0775 mode = 0775
url = {{ ru_lopcomm_software_template }} url = {{ ru_lopcomm_software_template }}
output = ${directory:script}/{{ru_ref}}-software.py output = ${directory:script}/{{B('%s-software.py' % ru_ref)}}
{%- if not testing %} {%- if not testing %}
{{ promise('%s-firmware' % ru_ref) }} {{ promise('%s-firmware' % ru_ref) }}
promise = check_command_execute promise = check_command_execute
config-command = [ -f ${ {{-ru_ref}}-software-template:is_firmware_updated} ] config-command = [ -f ${ {{-B('%s-software-template' % ru_ref)}}:is_firmware_updated} ]
{%- endif %} {%- endif %}
{#- push config to RU #} {#- push config to RU #}
{% if slapparameter_dict.get("cu_config_link", None) %} {% if ru.get("cu_config_link", None) %}
[cu-config-dl] [{{ B('%s-cu-config-dl' % ru_ref) }}]
recipe = slapos.recipe.build:download recipe = slapos.recipe.build:download
url = {{ slapparameter_dict.get("cu_config_link") }} url = {{ ru.cu_config_link }}
version = {{ slapparameter_dict.get("cu_config_version") }} version = {{ ru.get("cu_config_version") }}
offline = false offline = false
{% endif %} {% endif %}
[{{ru_ref}}-cu-config] [{{ B('%s-cu-config' % ru_ref) }}]
<= config-base <= config-base
{% if slapparameter_dict.get("cu_config_link", None) %} {% if ru.get("cu_config_link", None) %}
url = ${cu-config-dl:target} url = ${ {{-B('%s-cu-config-dl' % ru_ref)}}:target}
{% else %} {% else %}
url = {{ ru_lopcomm_cu_config_template }} url = {{ ru_lopcomm_cu_config_template }}
{% endif %} {% endif %}
output = ${directory:etc}/{{ru_ref}}-cu_config.xml output = ${directory:etc}/{{B('%s-cu_config.xml' % ru_ref)}}
extra-context =
[{{ru_ref}}-config-template] import xearfcn_module xlte.earfcn
import xnrarfcn_module xlte.nrarfcn
key ru :ru
key cell :cell
ru = {{ dumps(ru) }}
cell = {{ dumps(cell) }}
[{{ B('%s-config-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do extensions = jinja2.ext.do
log-output = ${directory:var}/log/{{ru_ref}}-config.log log-output = ${directory:var}/log/{{B('%s-config.log' % ru_ref)}}
context = context =
section directory directory section directory directory
section vtap vtap.{{ cell._tap }} section vtap vtap.{{ ru.cpri_link._tap }}
key log_file :log-output key log_file :log-output
raw testing {{ testing }} raw testing {{ testing }}
raw python_path {{ buildout_directory}}/bin/pythonwitheggs raw python_path {{ buildout_directory}}/bin/pythonwitheggs
raw buildout_directory_path {{ buildout_directory }} raw buildout_directory_path {{ buildout_directory }}
raw CreateProcessingEle_template {{ ru_lopcomm_CreateProcessingEle_template }} raw CreateProcessingEle_template {{ ru_lopcomm_CreateProcessingEle_template }}
key cu_config_template {{ru_ref}}-cu-config:output key cu_config_template {{B('%s-cu-config' % ru_ref)}}:output
import netaddr netaddr import netaddr netaddr
mode = 0775 mode = 0775
url = {{ ru_lopcomm_config_template }} url = {{ ru_lopcomm_config_template }}
output = ${directory:script}/{{ru_ref}}-config.py output = ${directory:script}/{{B('%s-config.py' % ru_ref)}}
{{ promise('%s-config-log' % ru_ref) }} {{ promise('%s-config-log' % ru_ref) }}
promise = check_lopcomm_config_log promise = check_lopcomm_config_log
config-config-log = ${ {{- ru_ref}}-config-template:log-output} config-config-log = ${ {{-B('%s-config-template' % ru_ref)}}:log-output}
{#- handle notifications from RU + keep on touching RU watchdog #} {#- handle notifications from RU + keep on touching RU watchdog #}
[{{ru_ref}}-stats-template] [{{ B('%s-stats-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}} _logbase = ${directory:var}/log/{{B('%s' % ru_ref)}}
log-output = ${:_logbase}-stats.log log-output = ${:_logbase}-stats.log
json-log-output = ${:_logbase}-stats.json.log json-log-output = ${:_logbase}-stats.json.log
cfg-json-log-output = ${:_logbase}-config.json.log cfg-json-log-output = ${:_logbase}-config.json.log
...@@ -101,11 +116,11 @@ supervision-json-log-output = ${:_logbase}-supervision.json.log ...@@ -101,11 +116,11 @@ supervision-json-log-output = ${:_logbase}-supervision.json.log
ncsession-json-log-output = ${:_logbase}-ncsession.json.log ncsession-json-log-output = ${:_logbase}-ncsession.json.log
software-json-log-output = ${:_logbase}-software.json.log software-json-log-output = ${:_logbase}-software.json.log
supervision-reply-json-log-output = ${:_logbase}-supervision-reply.json.log supervision-reply-json-log-output = ${:_logbase}-supervision-reply.json.log
is_netconf_connected = ${directory:etc}/{{ru_ref}}.is_netconf_connected is_netconf_connected = ${directory:etc}/{{B('%s.is_netconf_connected' % ru_ref)}}
context = context =
section directory directory section directory directory
section vtap vtap.{{ cell._tap }} section vtap vtap.{{ ru.cpri_link._tap }}
key slapparameter_dict slap-configuration:configuration key slapparameter_dict myslap:parameter_dict
key log_file :log-output key log_file :log-output
key json_log_file :json-log-output key json_log_file :json-log-output
key cfg_json_log_file :cfg-json-log-output key cfg_json_log_file :cfg-json-log-output
...@@ -120,12 +135,12 @@ context = ...@@ -120,12 +135,12 @@ context =
import netaddr netaddr import netaddr netaddr
mode = 0775 mode = 0775
url = {{ ru_lopcomm_stats_template }} url = {{ ru_lopcomm_stats_template }}
output = ${directory:bin}/{{ru_ref}}-stats.py output = ${directory:bin}/{{B('%s-stats.py' % ru_ref)}}
{{ part('%s-stats-service' % ru_ref) }} {{ part('%s-stats-service' % ru_ref) }}
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
command-line = ${ {{- ru_ref}}-stats-template:output} command-line = ${ {{-B('%s-stats-template' % ru_ref)}}:output}
wrapper-path = ${directory:service}/{{ru_ref}}-stats wrapper-path = ${directory:service}/{{B('%s-stats' % ru_ref)}}
mode = 0775 mode = 0775
hash-files = hash-files =
${:command-line} ${:command-line}
...@@ -133,50 +148,50 @@ hash-files = ...@@ -133,50 +148,50 @@ hash-files =
{%- if not testing %} {%- if not testing %}
{{ promise('%s-netconf-connection' % ru_ref) }} {{ promise('%s-netconf-connection' % ru_ref) }}
promise = check_command_execute promise = check_command_execute
config-command = [ -f ${ {{-ru_ref}}-stats-template:is_netconf_connected} ] config-command = [ -f ${ {{-B('%s-stats-template' % ru_ref)}}:is_netconf_connected} ]
{%- endif %} {%- endif %}
{{ promise('%s-vswr' % ru_ref) }} {{ promise('%s-vswr' % ru_ref) }}
promise = check_lopcomm_vswr promise = check_lopcomm_vswr
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output} config-netconf-log = ${ {{-B('%s-stats-template' % ru_ref)}}:json-log-output}
{{ promise('%s-rssi' % ru_ref) }} {{ promise('%s-rssi' % ru_ref) }}
promise = check_lopcomm_rssi promise = check_lopcomm_rssi
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output} config-netconf-log = ${ {{-B('%s-stats-template' % ru_ref)}}:json-log-output}
{{ promise('%s-pa-current' % ru_ref) }} {{ promise('%s-pa-current' % ru_ref) }}
promise = check_lopcomm_pa_current promise = check_lopcomm_pa_current
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output} config-netconf-log = ${ {{-B('%s-stats-template' % ru_ref)}}:json-log-output}
{{ promise('%s-pa-output-power' % ru_ref) }} {{ promise('%s-pa-output-power' % ru_ref) }}
promise = check_lopcomm_pa_output_power promise = check_lopcomm_pa_output_power
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output} config-netconf-log = ${ {{-B('%s-stats-template' % ru_ref)}}:json-log-output}
{{ promise('%s-sync' % ru_ref) }} {{ promise('%s-sync' % ru_ref) }}
promise = check_lopcomm_sync promise = check_lopcomm_sync
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output} config-netconf-log = ${ {{-B('%s-stats-template' % ru_ref)}}:json-log-output}
{{ promise('%s-lof' % ru_ref) }} {{ promise('%s-lof' % ru_ref) }}
promise = check_lopcomm_lof promise = check_lopcomm_lof
config-netconf-log = ${ {{- ru_ref}}-stats-template:json-log-output} config-netconf-log = ${ {{-B('%s-stats-template' % ru_ref)}}:json-log-output}
{{ promise('%s-stats-log' % ru_ref) }} {{ promise('%s-stats-log' % ru_ref) }}
promise = check_lopcomm_stats_log promise = check_lopcomm_stats_log
config-stats-log = ${ {{- ru_ref}}-stats-template:log-output} config-stats-log = ${ {{-B('%s-stats-template' % ru_ref)}}:log-output}
{#- reset RU periodically #} {#- reset RU periodically #}
{%- if slapparameter_dict.get("cron_schedule") %} {%- if ru.get("reset_schedule") %}
[{{ru_ref}}-reset-info-template] [{{ B('%s-reset-info-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-reset-info _logbase = ${directory:var}/log/{{B('%s-reset-info' % ru_ref)}}
log-output = ${:_logbase}.log log-output = ${:_logbase}.log
json-log-output = ${:_logbase}.json.log json-log-output = ${:_logbase}.json.log
context = context =
section vtap vtap.{{ cell._tap }} section vtap vtap.{{ ru.cpri_link._tap }}
key log_file :log-output key log_file :log-output
key json_log_file :json-log-output key json_log_file :json-log-output
raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }} raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
...@@ -185,35 +200,35 @@ context = ...@@ -185,35 +200,35 @@ context =
import netaddr netaddr import netaddr netaddr
mode = 0775 mode = 0775
url = {{ ru_lopcomm_reset_info_template }} url = {{ ru_lopcomm_reset_info_template }}
output = ${directory:bin}/{{ru_ref}}-reset-info.py output = ${directory:bin}/{{B('%s-reset-info.py' % ru_ref)}}
[{{ru_ref}}-reset-template] [{{ B('%s-reset-template' % ru_ref) }}]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{ru_ref}}-reset _logbase = ${directory:var}/log/{{B('%s-reset' % ru_ref)}}
log-output = ${:_logbase}.log log-output = ${:_logbase}.log
json-log-output = ${:_logbase}.json.log json-log-output = ${:_logbase}.json.log
context = context =
section vtap vtap.{{ cell._tap }} section vtap vtap.{{ ru.cpri_link._tap }}
key log_file :log-output key log_file :log-output
raw python_path {{ buildout_directory}}/bin/pythonwitheggs raw python_path {{ buildout_directory}}/bin/pythonwitheggs
raw buildout_directory_path {{ buildout_directory }} raw buildout_directory_path {{ buildout_directory }}
import netaddr netaddr import netaddr netaddr
mode = 0775 mode = 0775
url = {{ ru_lopcomm_reset_template }} url = {{ ru_lopcomm_reset_template }}
output = ${directory:etc}/{{ru_ref}}-reset.py output = ${directory:etc}/{{B('%s-reset.py' % ru_ref)}}
{{ part('%s-reset-cron' % ru_ref) }} {{ part('%s-reset-cron' % ru_ref) }}
recipe = slapos.cookbook:cron.d recipe = slapos.cookbook:cron.d
cron-entries = ${cron:cron-entries} cron-entries = ${cron:cron-entries}
name = {{ru_ref}}-reset name = {{B('%s-reset' % ru_ref)}}
frequency = {{ slapparameter_dict.get("cron_schedule", "") }} frequency = {{ ru.reset_schedule }}
command = {{ buildout_directory}}/bin/pythonwitheggs ${ {{- ru_ref}}-reset-template:output} command = {{ buildout_directory}}/bin/pythonwitheggs ${ {{-B('%s-reset-template' % ru_ref)}}:output}
{{ part('%s-reset-info-service' % ru_ref) }} {{ part('%s-reset-info-service' % ru_ref) }}
recipe = slapos.cookbook:wrapper recipe = slapos.cookbook:wrapper
command-line = ${ {{- ru_ref}}-reset-info-template:output} command-line = ${ {{-B('%s-reset-info-template' % ru_ref)}}:output}
wrapper-path = ${directory:service}/{{ru_ref}}-reset-info wrapper-path = ${directory:service}/{{B('%s-reset-info' % ru_ref)}}
mode = 0775 mode = 0775
hash-files = hash-files =
${:command-line} ${:command-line}
...@@ -221,13 +236,11 @@ hash-files = ...@@ -221,13 +236,11 @@ hash-files =
{%- endif %} {%- endif %}
{#- amend published information with Lopcomm-specific bits {#- amend RU-published information with Lopcomm-specific bits #}
TODO make it per-RU #} [{{ B('ipublish-%s' % ru_ref) }}]
[publish-connection-information] bbu-ssh-command = ssh ${user-info:pw-name}@${sshd-service:ipv6} -p ${sshd-service:port}
ssh-command = ssh ${user-info:pw-name}@${sshd-service:ipv6} -p ${sshd-service:port} bbu-ssh-url = ssh://${user-info:pw-name}@[${sshd-service:ipv6}]:${sshd-service:port}
ssh-url = ssh://${user-info:pw-name}@[${sshd-service:ipv6}]:${sshd-service:port} firmware = {{ru_lopcomm_firmware_filename}}
ru-firmware = {{ru_lopcomm_firmware_filename}}
ru-ipv6 = ${slap-configuration:tap-ipv6-gateway}
{%- endmacro %} {%- endmacro %}
...@@ -235,6 +248,10 @@ ru-ipv6 = ${slap-configuration:tap-ipv6-gateway} ...@@ -235,6 +248,10 @@ ru-ipv6 = ${slap-configuration:tap-ipv6-gateway}
{%- macro buildout() %} {%- macro buildout() %}
# deploy openssh-server for software upgrade # deploy openssh-server for software upgrade
#
# FIXME user-authorized-key is global for eNB. Either we need to put SSH server
# to be also global, or unroll an SSH server via paramiko inside
# ru/lopcomm/software.py just to handle software upgrades there.
[user-info] [user-info]
recipe = slapos.cookbook:userinfo recipe = slapos.cookbook:userinfo
...@@ -242,7 +259,7 @@ recipe = slapos.cookbook:userinfo ...@@ -242,7 +259,7 @@ recipe = slapos.cookbook:userinfo
recipe = slapos.cookbook:free_port recipe = slapos.cookbook:free_port
minimum = 22222 minimum = 22222
maximum = 22231 maximum = 22231
ip = ${slap-configuration:ipv6-random} ip = {{my_ipv6}}
[sshd-config] [sshd-config]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
......
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by Radio Unit instantiation (stub)",
"type": "object",
"properties": {}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "SDR transiever",
"description": "Radio Unit constituted of several SDR boards",
"type": "object",
"required": [
"ru_type",
"ru_link_type",
"n_antenna_dl",
"n_antenna_ul",
"tx_gain",
"rx_gain",
"sdr_dev_list"
],
"properties": {
"$ref": "../../ru/common.json#/properties",
"ru_type": {
"$ref": "#/properties/ru_type",
"const": "sdr",
"template": "sdr"
},
"ru_link_type": {
"$ref": "#/properties/ru_link_type",
"const": "sdr",
"template": "sdr"
},
"sdr_dev_list": {
"title": "SDR boards",
"description": "Which SDR boards to use as combined RF port",
"type": "array",
"items": {
"title": "/dev/sdr # of SDR board",
"type": "integer"
},
"minItems": 1,
"uniqueItems": true
}
}
}
{#- 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, cell) %} {%- macro buildout_iru(iru, icell_list) %}
{#- nothing SDR-specific #} {#- nothing SDR-specific #}
{%- endmacro %} {%- endmacro %}
......
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Sunwave M2RU",
"type": "object",
"required": [
"ru_type",
"ru_link_type",
"n_antenna_dl",
"n_antenna_ul",
"tx_gain",
"rx_gain",
"cpri_link",
"mac_addr"
],
"properties": {
"$ref": "../../ru/common.json#/properties",
"ru_type": {
"$ref": "#/properties/ru_type",
"const": "sunwave",
"template": "sunwave"
},
"ru_link_type": {
"$ref": "#/properties/ru_link_type",
"const": "cpri",
"template": "cpri"
},
"n_antenna_dl": {
"$ref": "#/properties/n_antenna_dl",
"default": 2
},
"n_antenna_ul": {
"$ref": "#/properties/n_antenna_ul",
"default": 1
},
"cpri_link": {
"$ref": "#/properties/cpri_link",
"properties": {
"$ref": "#/properties/cpri_link/properties",
"mapping": {
"$ref": "#/properties/cpri_link/properties/mapping",
"const": "bf1",
"enum": ["bf1"],
"options": { "hidden": true }
},
"rx_delay": {
"$ref": "#/properties/cpri_link/properties/rx_delay",
"default": 11.0
},
"tx_dbm": {
"$ref": "#/properties/cpri_link/properties/tx_dbm",
"default": 42.0
}
}
}
}
}
{#- 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, cell) %} {%- macro buildout_iru(iru, icell_list) %}
{#- nothing SunWave-specific #} {#- nothing SunWave-specific #}
{%- endmacro %} {%- endmacro %}
......
#!/usr/bin/env python #!/usr/bin/env python
# Copyright (C) 2023 Nexedi SA and Contributors. # Copyright (C) 2023-2024 Nexedi SA and Contributors.
# #
# This program is free software: you can Use, Study, Modify and Redistribute # This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your # it under the terms of the GNU General Public License version 3, or (at your
...@@ -34,38 +34,98 @@ from math import log2, ceil ...@@ -34,38 +34,98 @@ from math import log2, ceil
import sys import sys
import subprocess import subprocess
import json
# LinkDB represents snapshot of state of all network interfaces.
class LinkDB:
def __init__(db):
db.linkv = ip('link', 'show')
# ifget returns information about interface with specified name.
def ifget(db, ifname):
for link in db.linkv:
if link['ifname'] == ifname:
return link
raise KeyError('interface %r not found' % ifname)
def main(): def main():
tap = sys.argv[1] tap = sys.argv[1]
n = int(sys.argv[2]) n = int(sys.argv[2])
assert n >= 0, n assert n >= 0, n
# determine tap's network address and owner # determine tap's network address and owner
owner = readfile(sysnet(tap) + '/owner') .strip() ldb = LinkDB()
_ = ldb.ifget(tap)
owner = _['linkinfo']['info_data']['user']
net = ifnet6(tap) net = ifnet6(tap)
print('%s: split %s by %d' % (tap, net, n)) print('%s: split %s by %d' % (tap, net, n))
# cleanup existing children
for ifname in netifaces.interfaces():
if ifname.startswith('%s-' % tap):
run('ip', 'link', 'del', ifname)
# do the split # do the split
# with leaving first range for the original tap # with leaving first range for the original tap
subtap_set = set()
for i, subnet in enumerate(netsplit(net, 1+n)): for i, subnet in enumerate(netsplit(net, 1+n)):
if i == 0: if i == 0:
print('preserve %s' % subnet) print('preserve %s' % subnet)
continue # leave this range for original tap continue # leave this range for original tap
subtap = '%s-%d' % (tap, i) subtap = '%s-%d' % (tap, i)
subtap_set.add(subtap)
print('-> %s %s' % (subtap, subnet)) print('-> %s %s' % (subtap, subnet))
def note(msg):
print(' # %s: %s' % (subtap, msg))
# create subtap
try:
link = ldb.ifget(subtap)
except KeyError:
run('ip', 'tuntap', 'add', 'dev', subtap, 'mode', 'tap', 'user', owner) run('ip', 'tuntap', 'add', 'dev', subtap, 'mode', 'tap', 'user', owner)
link = ip('link', 'show', 'dev', subtap)[0]
else:
note('already exists')
# set it up
if 'UP' not in link['flags']:
run('ip', 'link', 'set', subtap, 'up') run('ip', 'link', 'set', subtap, 'up')
else:
note('already up')
# add subnet address
addrv = []
for _ in ip('-6', 'addr', 'show', 'dev', subtap):
addrv.extend(_['addr_info'])
for addr in addrv:
_ = netaddr.IPNetwork('%s/%s' % (addr['local'], addr['prefixlen']))
if _ == subnet and addr['noprefixroute']:
note('already has %s addr' % str(subnet))
break
else:
run('ip', 'addr', 'add', str(subnet), 'dev', subtap, 'noprefixroute') run('ip', 'addr', 'add', str(subnet), 'dev', subtap, 'noprefixroute')
# add /128 route to subnet::1
rtv = ip('-6', 'route', 'show', 'dev', subtap)
for rt in rtv:
if rt['dst'] == str(subnet[1]) and 'gateway' not in rt:
note('already has %s route' % str(subnet[1]))
break
else:
run('ip', 'route', 'add', str(subnet[1]), 'dev', subtap) run('ip', 'route', 'add', str(subnet[1]), 'dev', subtap)
# add route to subnet via subnet::1
for rt in rtv:
if rt['dst'] == str(subnet) and rt.get('gateway') == str(subnet[1]):
note('already has %s route' % str(subnet))
break
else:
run('ip', 'route', 'add', str(subnet), 'dev', subtap, 'via', str(subnet[1])) run('ip', 'route', 'add', str(subnet), 'dev', subtap, 'via', str(subnet[1]))
# remove other existing children
for ifname in netifaces.interfaces():
if ifname.startswith('%s-' % tap) and (ifname not in subtap_set):
print('-> del %s' % ifname)
run('ip', 'link', 'del', ifname)
# netsplit splits network into n subnetworks. # netsplit splits network into n subnetworks.
def netsplit(net, n): # -> []subnet def netsplit(net, n): # -> []subnet
...@@ -102,17 +162,15 @@ def ifnet6(ifname): ...@@ -102,17 +162,15 @@ def ifnet6(ifname):
net = net.cidr net = net.cidr
return net return net
# sysnet returns path on /sys corresponding to given interface. # run executes `*argv` as action.
def sysnet(ifname):
return '/sys/devices/virtual/net/%s' % ifname
def run(*argv): def run(*argv):
print(' # %s' % ' '.join(argv)) print(' # %s' % ' '.join(argv))
subprocess.check_call(argv) subprocess.check_call(argv)
def readfile(path): # ip returns decoded output of `ip -details *argv`
with open(path) as f: def ip(*argv):
return f.read() _ = subprocess.check_output(['ip', '-json', '-details'] + list(argv))
return json.loads(_)
if __name__ == '__main__': if __name__ == '__main__':
......
# Copyright (C) 2023-2024 Nexedi SA and Contributors.
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
"""Package xbuildout provides additional buildout-related utilities.
- encode/decode convert string to/from form, that is suitable to be used in
names of buildout sections.
"""
# encode converts string s into form suitable to be used in names of buildout sections.
#
# Such encoding is needed because buildout forbids to use spaces and many other
# characters in section names, which, in turn, leads to inability to directly
# use arbitrary strings for sections generated based on e.g. instance
# references retrieved from SlapOS Master.
#
# With encoding it becomes possible to use arbitrary names for references
# without leading to instantiation failures like
#
# zc.buildout.configparser.ParsingError: File contains parsing errors: .../instance-enb.cfg
# [line 45]: '[promise-testing partition 0.RU-sdr-busy]\n'
#
# and without being vulnerable to buildout code injection.
#
# The encoding never fails, does not loose information and can be reversed back via decode.
#
# It also leaves all characters allowed by buildout except "_" as is, which
# makes encoding to be identity for 99% of the practical cases in existing
# SlapOS profiles. In other words it is safe to use encode for both generated
# and static buildout sections, without the need to also use encode when
# referring to those static sections.
#
# Recommended usage of encode in buildout profiles is via B as illustrated below:
#
# {#- B(name) escapes name to be safe to use in buildout code. #}
# {%- set B = xbuildout.encode %}
#
# ...
#
# [{{ B('%s-stats' % ru_ref) }}]
# # code for <ru_ref>-stats section
#
# ...
#
# # referring to <ru_ref>-stats
# ${ {{-B('%s-stats' % ru_ref)}}:output}
#
#
# See also `dumps` in buildout for a way to serialize option values with
# protection against code injection:
#
# https://lab.nexedi.com/nexedi/slapos.buildout/commit/4e13dcb9
# https://lab.nexedi.com/nexedi/slapos.recipe.template/commit/84dc7957
def encode(s: str) -> str:
s = s.encode('utf-8')
outv = []
emit = outv.append
for c in s:
c = bytes([c]) # int -> bytechar
# _ serves as escape character
if c == b'_':
emit(b'__')
# other characters allowed by buildout go as is
elif (b'a' <= c <= b'z') or \
(b'A' <= c <= b'Z') or \
(b'0' <= c <= b'9') or \
(c in b'.-'):
emit(c)
# all other bytes go as escaped hex
else:
emit(b'_%02x' % ord(c))
out = b''.join(outv)
out = out.decode('utf-8') # should not fail
return out
# decode provides reverse operation for encode.
def decode(s: str): # -> str | ValueError
try:
return _decode(s)
except Exception as e:
raise ValueError("invalid encoding: %r" % s) from e
def _decode(s):
s = s.encode('utf-8')
outv = []
emit = outv.append
while len(s) > 0:
c = s[:1]
s = s[1:]
if c != b'_':
emit(c)
continue
if len(s) < 1:
raise ValueError("truncated escape sequence")
x = s[:1]
s = s[1:]
if x == b'_':
emit(b'_')
continue
if len(s) < 1:
raise ValueError("truncated escape sequence")
x += s[:1]
s = s[1:]
i = int(x, 16) # raises ValueError if not ok
c = bytes([i])
emit(c)
out = b''.join(outv)
out = out.decode('utf-8') # raises UnicodeDecodeError if it was invalid UTF-8
return out
# ----------------------------------------
import re
def test_encode():
# verify all ascii characters one by one
bok = re.compile(r'[a-zA-Z0-9.-]') # characters that are ok to use in buildout except '_'
for i in range(0x80):
c = chr(i)
e = encode(c)
if bok.match(c):
assert e == c
elif c == '_':
assert e == '__'
else:
assert e == '_%02x' % i
assert decode(e) == c
# also explicitly test several example cases, including unicode
testv = [
# s encoded
('', ''),
('a', 'a'),
('ayzAYZ09.-', 'ayzAYZ09.-'),
('_', '__'),
(' ', '_20'),
('αβγ', '_ce_b1_ce_b2_ce_b3'),
('a b+c_d', 'a_20b_2bc__d'),
]
for (s, encok) in testv:
assert encode(s) == encok
assert decode(encok) == s
# decode errors
from pytest import raises
def checkbad(x, f):
with raises(ValueError, match="invalid encoding") as exci:
decode(x)
cause = exci.value.__cause__
f(cause)
for x in ('_', '_1', 'a_2'):
def _(cause):
assert isinstance(cause, ValueError)
assert cause.args == ("truncated escape sequence",)
checkbad(x, _)
for x in ('_1r', '_r1', 'a_xy'):
def _(cause):
assert isinstance(cause, ValueError)
assert len(cause.args) == 1
assert cause.args[0] .startswith("invalid literal for int() with base 16:")
checkbad(x, _)
for x in ('_c3_28', '_e2_28_a1'):
def _(cause):
assert isinstance(cause, UnicodeDecodeError)
checkbad(x, _)
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by SIM Card instantiation (stub)",
"type": "object",
"properties": {}
}
{#- Package slaplte provides helpers for configuring Amarisoft LTE services in SlapOS. {#- Package slaplte provides helpers for configuring Amarisoft LTE services in SlapOS.
- load_cell initializes cell registry. - load_iru_and_icell initializes RU and cell registries.
- load_ipeercell initializes peer-cell registry.
- load_ipeer initializes peer registry.
- load_iue initializes UE registry.
- ru_config emits RF driver configuration for specified Radio Units.
In the code iX denotes shared instance of type X, while X denotes
parameters passed to iX. For example iru denotes Radio Unit shared
instance, while ru denotes parameters of that Radio Unit instance.
The following utilities are also provided: The following utilities are also provided:
- B escapes string to be safe to use in buildout code.
- J should be used around macro calls to retrieve returned objects. - J should be used around macro calls to retrieve returned objects.
- error reports instantiation error. - error reports instantiation error.
- ierror reports instantiation error caused by shared instance configuration.
-#} -#}
{#- defaults provide default values for lte parameters.
it should be kept in sync with "default" in json schemas
TODO automatically load defaults from JSON schemas #}
{%- set defaults = {
'ru': {
'txrx_active': 'INACTIVE',
},
'ru/cpri_link': {
'mult': 16,
'rx_delay': 0,
'tx_delay': 0,
'tx_dbm': 0,
},
'ru/lopcomm': {
'n_antenna_dl': 2,
'n_antenna_ul': 2,
},
'ru/lopcomm/cpri_link': {
'mapping': 'hw',
'rx_delay': 25.11,
'tx_delay': 14.71,
'tx_dbm': 63,
},
'ru/sunwave': {
'n_antenna_dl': 2,
'n_antenna_ul': 1,
},
'ru/sunwave/cpri_link': {
'mapping': 'bf1',
'rx_delay': 11.0,
'tx_dbm': 42.0,
},
'cell/lte': {
'inactivity_timer': 10000,
},
'cell/lte/fdd': {
},
'cell/lte/tdd': {
'tdd_ul_dl_config': '[Configuration 2] 5ms 2UL 6DL (default)',
},
'cell/nr': {
'inactivity_timer': 10000,
},
'cell/nr/fdd': {
'ssb_pos_bitmap': '1000',
},
'cell/nr/tdd': {
'ssb_pos_bitmap': '10000000',
'tdd_ul_dl_config': '5ms 2UL 7DL 4/6 (default)',
},
'ue': {
'sim_algo': 'milenage',
'opc': 'milenage',
'amf': '0x9001',
'sqn': '000000000000',
'impu': '',
'impi': '',
'imsi': '001010123456789',
'k': '00112233445566778899aabbccddeeff',
},
}
%}
{#- B(name) escapes name to be safe to use in buildout code.
It escapes buildout control characters in the string so that the result
could be used in buildout code without the risk of buildout profile to
become broken and/or with injected code when handling string input from
outside.
The most often case when B needs to be used is when handling references of
shared instances in generated buildout code.
See xbuildout.encode documentation for details.
#}
{%- set B = xbuildout.encode %}
{#- J is used around macro calls to retrieve returned objects. {#- J is used around macro calls to retrieve returned objects.
It is needed to workaround jinja2 limitation that macro can return only It is needed to workaround jinja2 limitation that macro can return only
...@@ -23,6 +117,24 @@ ...@@ -23,6 +117,24 @@
#} #}
{%- set J = json_module.loads %} {%- set J = json_module.loads %}
{#- jdefault_ul_earfcn returns default UL EARFCN corresponding to DL EARFCN. #}
{%- macro jdefault_ul_earfcn(dl_earfcn) %}
{{- xearfcn_module.dl2ul(dl_earfcn) | tojson }}
{%- endmacro %}
{#- jdefault_ul_nr_arfcn returns default UL NR ARFCN corresponding to DL NR ARFCN and band. #}
{%- macro jdefault_ul_nr_arfcn(dl_nr_arfcn, nr_band) %}
{{- xnrarfcn_module.dl2ul(dl_nr_arfcn, nr_band) | tojson }}
{%- endmacro %}
{#- jdefault_ssb_nr_arfcn returns default SSB NR ARFCN corresponding to DL NR ARFCN
and band. #}
{%- macro jdefault_ssb_nr_arfcn(dl_nr_arfcn, nr_band) %}
{#- NOTE: computations rechecked wrt https://tech-academy.amarisoft.com/OutOfBox_UEsim_SA.html#Tips_SSB_Frequency #}
{%- set ssb_nr_arfcn, max_ssb_scs_khz = xnrarfcn_module.dl2ssb(dl_nr_arfcn, nr_band) %}
{{- ssb_nr_arfcn | tojson }}
{%- endmacro %}
{#- tap indicates tap interface, that slapos told us to use, {#- tap indicates tap interface, that slapos told us to use,
or 'xxx-notap-xxx' if slapos provided us either nothing or empty string. #} or 'xxx-notap-xxx' if slapos provided us either nothing or empty string. #}
...@@ -44,29 +156,374 @@ ...@@ -44,29 +156,374 @@
{%- do assert(False, msg) %} {%- do assert(False, msg) %}
{%- endmacro %} {%- endmacro %}
{#- ierror reports instantiation error caused by shared instance configuration. #}
{%- macro ierror(ishared, msg) %}
{%- do error('%s: %s' % (J(jref_of_shared(ishared)), msg)) %}
{%- endmacro %}
{#- ---- loading ---- #} {#- ---- loading ---- #}
{#- load_cell initializes cell registry. {#- jref_of_shared returns original reference used to request shared instance.
slapproxy puts the reference into slave_reference and slave_title as <partition_id>_<reference>.
slapos master puts the reference into slave_title as-is and assigns to slave_reference SOFTINST-XXX.
cell_list keeps configured cells: {} cell reference -> cell parameters -> we extract the reference from slave_title.
#} #}
{%- macro load_cell(cell_list) %} {%- macro jref_of_shared(ishared) %}
{%- do cell_list.update( slapparameter_dict.get('cell_list', {'default': {}}) ) %} {#- do print('jref_of_shared %r' % (ishared,)) #}
{%- for i, k in enumerate(cell_list) %} {%- set ref = ishared['slave_title'] %}
{%- set cell = cell_list[k] %} {%- set partition_id = slap_configuration['slap-computer-partition-id'] %}
{%- do cell.setdefault('cpri_port_number', i) %} {%- if ref.startswith(partition_id) %}
{%- set ref = ref[len(partition_id):] %}
{%- endif %}
{%- set ref = ref.removeprefix('_') %}
{{- ref | tojson }}
{%- endmacro %}
{#- qshared_instance_list queues not yet loaded shared instances.
load_* routines process this queue and move loaded instances to i<type>_dict registries. #}
{%- set qshared_instance_list = slap_configuration.get('slave-instance-list', []) %}
{#- protect against duplicate slave_title -- see jref_of_shared for why we need this #}
{%- for i, ishared in enumerate(qshared_instance_list) %}
{%- for k, kshared in enumerate(qshared_instance_list) %}
{%- if i != k and ishared.slave_title == kshared.slave_title %}
{%- do ierror(ishared, 'duplicate title wrt %s' % kshared.slave_reference) %}
{%- endif %}
{%- endfor %}
{%- endfor %} {%- endfor %}
{#- assign TAP interfaces to RUs #} {#- check_loaded_everything verifies that all shared instances were handling during the load. #}
{%- for i, (cell_ref, cell) in enumerate(cell_list|dictsort) %} {%- macro check_loaded_everything() %}
{%- if len(cell_list) > 1 %} {%- for ishared in qshared_instance_list %}
{%- do ierror(ishared, "shared instance of unsupported type") %}
{%- endfor %}
{%- endmacro %}
{#- json-decode _ in all shared instances #}
{%- for ishared in qshared_instance_list %}
{%- do ishared.update({'_': J(ishared['_'])}) %}
{%- endfor %}
{#- load_iru_and_icell initializes RU and cell registries.
icell_dict keeps cell shared instances: reference -> icell
iru_dict keeps RU shared instances + RU whose definition is embedded into a cell: reference -> iRU
in the kept instances _ is automatically json-decoded
icell_kind=enb - load cells definition to serve them from enb
icell_kind=ue - load cells definition to connect to them
#}
{%- macro load_iru_and_icell(iru_dict, icell_dict, icell_kind) %}
{%- set qother = [] %}
{%- for ishared in qshared_instance_list %}
{%- set ref = J(jref_of_shared(ishared)) %}
{%- set _ = ishared['_'] %}
{%- if 'ru_type' in _ %}
{%- set iru = ishared %}
{%- do _ru_set_defaults(_) %}
{%- do iru_dict.update({ref: iru}) %}
{%- elif 'cell_type' in _ and _.get('cell_kind') == icell_kind %}
{%- set icell = ishared %}
{%- do _cell_set_defaults(_, icell_kind, icell_dict) %}
{%- do icell_dict.update({ref: icell}) %}
{%- set ru = _['ru'] %}
{%- if ru.ru_type not in ('ru_ref', 'ruincell_ref') %}
{#- embedded ru definition -> expose it as synthethic `_<cell_ref>_ru` #}
{%- do _ru_set_defaults(ru) %}
{%- do iru_dict.update({'_%s_ru' % ref: {
'_': ru,
'slave_title': '%s. RU' % icell.slave_title,
'slave_reference': False,
}}) %}
{%- endif %}
{%- else %}
{%- do qother.append(ishared) %}
{%- endif %}
{%- endfor %}
{%- do qshared_instance_list.clear() %}
{%- do qshared_instance_list.extend(qother) %}
{#- do print('\n>>> iru_dict:'), pprint(iru_dict) #}
{#- do print('\n>>> icell_dict:'), pprint(icell_dict) #}
{#- verify that there is no dangling cell -> cell refs in ruincell_ref #}
{%- for _, icell in icell_dict|dictsort %}
{%- set ru = icell['_']['ru'] %}
{%- if ru.ru_type == 'ruincell_ref' %}
{%- if ru.ruincell_ref not in icell_dict %}
{%- do ierror(icell, "referred cell %r does not exist" % ru.ruincell_ref) %}
{%- endif %}
{%- endif %}
{%- endfor %}
{#- verify that there is no dangling cell->ru references #}
{%- for _, icell in icell_dict|dictsort %}
{%- set ru_ref = J(jcell_ru_ref(icell, icell_dict)) %}
{%- if ru_ref not in iru_dict %}
{%- do ierror(icell, "referred RU %r does not exist" % ru_ref) %}
{%- endif %}
{%- endfor %}
{#- assign RUs rf_port and tx/rx channel indices #}
{%- set rf_chan = namespace(tx=0, rx=0) %}
{%- for rf_port, (ru_ref, iru) in enumerate(iru_dict|dictsort) %}
{%- set ru = iru['_'] %}
{%- do ru.update({'_rf_port': rf_port,
'_rf_chan_tx': rf_chan.tx,
'_rf_chan_rx': rf_chan.rx}) %}
{%- set rf_chan.tx = rf_chan.tx + ru.n_antenna_dl %}
{%- set rf_chan.rx = rf_chan.rx + ru.n_antenna_ul %}
{%- endfor %}
{#- assign TAP interfaces to cpri RUs #}
{%- set iru_vcpri = list(iru_dict|dictsort | selectattr('1._.ru_link_type', '==', 'cpri')) %}
{%- for i, (ru_ref, iru) in enumerate(iru_vcpri) %}
{%- if len(iru_vcpri) > 1 %}
{%- set ru_tap = "%s-%d" % (tap, i+1) %} {%- set ru_tap = "%s-%d" % (tap, i+1) %}
{%- else %} {%- else %}
{%- set ru_tap = tap %} {%- set ru_tap = tap %}
{%- endif %} {%- endif %}
{%- do cell.update({'_tap': ru_tap}) %} {%- do iru._.cpri_link.update({'_tap': ru_tap}) %}
{%- endfor %}
{%- endmacro %}
{%- macro _ru_set_defaults(ru) %}
{%- for k, v in defaults['ru'].items() %}
{%- do ru.setdefault(k, v) %}
{%- endfor %}
{%- for k, v in defaults.get('ru/'+ru.ru_type, {}).items() %}
{%- do ru.setdefault(k, v) %}
{%- endfor %}
{%- if ru.ru_link_type == 'cpri' %}
{%- set link = ru.cpri_link %}
{%- for k, v in defaults['ru/cpri_link'].items() %}
{%- do link.setdefault(k, v) %}
{%- endfor %}
{%- for k, v in defaults['ru/%s/cpri_link' % ru.ru_type].items() %}
{%- do link.setdefault(k, v) %}
{%- endfor %}
{%- endif %}
{%- endmacro %}
{%- macro _cell_set_defaults(cell, icell_kind, icell_dict) %}
{%- if icell_kind == 'enb' %}
{%- for k, v in defaults['cell/%s' % cell.cell_type].items() %}
{%- do cell.setdefault(k, v) %}
{%- endfor %}
{%- for k, v in defaults['cell/%s/%s' % (cell.cell_type, cell.rf_mode)].items() %}
{%- do cell.setdefault(k, v) %}
{%- endfor %} {%- endfor %}
{%- set n = len(list(icell_dict|dictsort | selectattr('1._.cell_type', '==', cell.cell_type))) %}
{%- do cell.setdefault('root_sequence_index', 1 + 203*(cell.cell_type == 'lte') + n) %}
{%- endif %}
{%- if cell.cell_type == 'lte' %}
{%- do cell.setdefault('ul_earfcn', J(jdefault_ul_earfcn(cell.dl_earfcn))) %}
{%- elif cell.cell_type == 'nr' %}
{%- do cell.setdefault('ul_nr_arfcn', J(jdefault_ul_nr_arfcn(cell.dl_nr_arfcn, cell.nr_band))) %}
{%- do cell.setdefault('subcarrier_spacing', 30 if cell.rf_mode == 'tdd' else 15) %}
{%- do cell.setdefault('ssb_nr_arfcn', J(jdefault_ssb_nr_arfcn(cell.dl_nr_arfcn, cell.nr_band))) %}
{%- else %}
{%- do bug('unreachable') %}
{%- endif %}
{%- endmacro %}
{#- jcell_ru_ref returns RU reference linked from a cell.
if the cell embeds RU definition, its reference comes as `_<cell_ref>_ru`. #}
{%- macro jcell_ru_ref(icell, icell_dict) %}
{{- _jcell_ru_ref(icell, icell_dict, []) }}
{%- endmacro %}
{%- macro _jcell_ru_ref(icell, icell_dict, seen) %}
{%- set cell_ref = J(jref_of_shared(icell)) %}
{%- if cell_ref in seen %}
{%- for x in seen %}
{%- do ierror(x, "%s form a cycle via RU references" % seen) %}
{%- endfor %}
{{- None | tojson }}
{%- else %}
{%- do seen.append(cell_ref) %}
{%- set ru = icell['_']['ru'] %}
{%- if ru.ru_type == 'ru_ref' %}
{{- ru.ru_ref | tojson }}
{%- elif ru.ru_type == 'ruincell_ref' %}
{{- _jcell_ru_ref(icell_dict[ru.ruincell_ref], icell_dict, seen) }}
{%- else %}
{#- ru definition is embedded into cell #}
{{- ('_%s_ru' % J(jref_of_shared(icell))) | tojson }}
{%- endif %}
{%- endif %}
{%- endmacro %}
{#- load_ipeer initializes peer registry.
ipeer_dict keeps peer shared instances: reference -> ipeer
#}
{%- macro load_ipeer(ipeer_dict) %}
{%- set qother = [] %}
{%- for ishared in qshared_instance_list %}
{%- set ref = J(jref_of_shared(ishared)) %}
{%- set _ = ishared['_'] %}
{%- if 'peer_type' in _ %}
{%- set ipeer = ishared %}
{%- do assert(_.peer_type in ('lte', 'nr')) %}
{%- do ipeer_dict.update({ref: ipeer}) %}
{%- else %}
{%- do qother.append(ishared) %}
{%- endif %}
{%- endfor %}
{%- do qshared_instance_list.clear() %}
{%- do qshared_instance_list.extend(qother) %}
{%- endmacro %}
{#- load_ipeercell initializes peer-cell registry.
ipeercell_dict keeps peer cell shared instances: reference -> ipeercell
#}
{%- macro load_ipeercell(ipeercell_dict) %}
{%- set qother = [] %}
{%- for ishared in qshared_instance_list %}
{%- set ref = J(jref_of_shared(ishared)) %}
{%- set _ = ishared['_'] %}
{%- if 'cell_type' in _ and _.get('cell_kind') == 'enb_peer' %}
{%- set ipeercell = ishared %}
{%- if _.cell_type == 'lte' %}
{%- do _.setdefault('ul_earfcn', J(jdefault_ul_earfcn(_.dl_earfcn))) %}
{%- elif _.cell_type == 'nr' %}
{%- do _.setdefault('ul_nr_arfcn', J(jdefault_ul_nr_arfcn(_.dl_nr_arfcn, _.nr_band))) %}
{%- do _.setdefault('subcarrier_spacing',
30 if nrarfcn_module.get_duplex_mode(_.nr_band).lower() == 'tdd' else
15) %}
{%- do _.setdefault('ssb_nr_arfcn', J(jdefault_ssb_nr_arfcn(_.dl_nr_arfcn, _.nr_band))) %}
{%- else %}
{%- do bug('unreachable') %}
{%- endif %}
{%- do ipeercell_dict.update({ref: ipeercell}) %}
{%- else %}
{%- do qother.append(ishared) %}
{%- endif %}
{%- endfor %}
{%- do qshared_instance_list.clear() %}
{%- do qshared_instance_list.extend(qother) %}
{%- endmacro %}
{#- load_iue initializes UE registry.
iue_dict keeps ue shared instance: reference -> iue
#}
{%- macro load_iue(iue_dict) %}
{%- set qother = [] %}
{%- for ishared in qshared_instance_list %}
{%- set ref = J(jref_of_shared(ishared)) %}
{%- set _ = ishared['_'] %}
{%- if 'ue_type' in _ %}
{%- set iue = ishared %}
{%- for k, v in defaults['ue'].items() %}
{%- do _.setdefault(k, v) %}
{%- endfor %}
{%- do iue_dict.update({ref: iue}) %}
{%- else %}
{%- do qother.append(ishared) %}
{%- endif %}
{%- endfor %}
{%- do qshared_instance_list.clear() %}
{%- do qshared_instance_list.extend(qother) %}
{%- endmacro %}
{#- ---- building configuration ---- #}
{#- ru_config emits RF driver configuration for specified Radio Units. #}
{%- macro ru_config(iru_dict, slapparameter_dict) %}
// Radio Units
rf_driver: {
{%- set dev_argv = [] %}
{%- set ru_sdr_dict = {} %} {#- dev -> ru for ru with ru_type = sdr #}
{%- set ru_cpri_dict = {} %} {#- dev -> ru for ru with link_type = cpri #}
{%- set tx_gainv = [] %} {#- tx_gain by tx channel #}
{%- set rx_gainv = [] %} {#- rx_gain by rx channel #}
{%- for (ru_ref, iru) in iru_dict.items() | sort(attribute="1._._rf_port") %}
{%- set ru = iru['_'] %}
// {{ B(ru_ref) }} {{ ru.n_antenna_dl }}T{{ ru.n_antenna_ul }}R ({{ ru.ru_type }})
{%- if ru.ru_link_type == 'sdr' %}
{%- do ru_sdr_dict.update({len(dev_argv): ru}) %}
{%- for n in ru.sdr_dev_list %}
{%- do dev_argv.append("dev%d=/dev/sdr%d" % (len(dev_argv), n)) %}
{%- endfor %}
{%- elif ru.ru_link_type == 'cpri' %}
{%- do ru_cpri_dict.update({len(dev_argv): ru}) %}
{%- set link = ru.cpri_link %}
{%- do dev_argv.append("dev%d=/dev/sdr%d@%d" % (len(dev_argv), link.sdr_dev, link.sfp_port)) %}
{%- else %}
{%- do bug('unreachable') %}
{%- endif %}
{%- set ru_tx_gain = ru.tx_gain if ru.txrx_active == 'ACTIVE' else -1000 %}
{%- do tx_gainv.extend([ru_tx_gain]*ru.n_antenna_dl) %}
{%- do rx_gainv.extend([ru.rx_gain]*ru.n_antenna_ul) %}
{%- endfor %}
{#- emit big error if both sdr and cpri are present
to protect users from unclear eNB failures in such unsupported combination #}
{%- set do_sdr = len(ru_sdr_dict) > 0 %}
{%- set do_cpri = len(ru_cpri_dict) > 0 %}
{%- if do_sdr and do_cpri %}
{%- do error('Mixing SDR + CPRI is not supported and breaks subtly.
SDR Radio Units: %r
CPRI Radio Units: %r
See https://support.amarisoft.com/issues/26021 for details' % (
iru_dict |dictsort |selectattr('1._.ru_type', '==', 'sdr') |map(attribute='0') |list,
iru_dict |dictsort |selectattr('1._.ru_link_type', '==', 'cpri') |map(attribute='0') |list
)) %}
{%- endif %}
{#- disable trx completely if all we have is only inactive sdr(s).
do not disable if there is cpri, because for cpri whether to activate
radio or not is natively controlled via RU-specific config.
See e.g. ru/lopcomm/cu_config.jinja2.xml for details #}
{%- if do_sdr and (not do_cpri) and
len(iru_dict|dictsort | selectattr('1._.txrx_active', '==', 'ACTIVE') | list) == 0 %}
name: "dummy",
{%- else %}
name: "sdr",
{%- endif %}
{%- if slapparameter_dict.get('gps_sync', False) %}
sync: "gps",
{%- endif %}
{#- below we continue as if sdr and cpri are both supported by enb simultaneously #}
args: "{{(dev_argv | join(',')) or '---'}}",
{%- if ors %}
rx_antenna:"tx_rx",
tdd_tx_mod: 1,
{%- endif %}
{#- emit cpri_* options if a cpri ru is present #}
{#- NOTE values for non-cpri links come as empty #}
{%- if do_cpri %}
{%- set vcpri = [None]*len(dev_argv) %}
{%- for dev, ru in ru_cpri_dict|dictsort %}
{%- do vcpri.__setitem__(dev, ru.cpri_link) %}
{%- endfor %}
cpri_mapping: "{{ vcpri | map(attribute='mapping') | map('default', '') | join(',') }}",
cpri_mult: "{{ vcpri | map(attribute='mult') | map('default', '') | join(',') }}",
cpri_rx_delay: "{{ vcpri | map(attribute='rx_delay') | map('default', '') | join(',') }}",
cpri_tx_delay: "{{ vcpri | map(attribute='tx_delay') | map('default', '') | join(',') }}",
cpri_tx_dbm: "{{ vcpri | map(attribute='tx_dbm') | map('default', '') | join(',') }}",
ifname: "{{ vcpri | map(attribute='_tap') | map('default', '') | join(',') }}",
{%- endif %}
},
{#- emit tx/rx gain for all channels #}
tx_gain: {{ tx_gainv }},
rx_gain: {{ rx_gainv }},
{%- endmacro %} {%- endmacro %}
...@@ -6,23 +6,36 @@ ...@@ -6,23 +6,36 @@
import zc.buildout.buildout # XXX workaround for https://lab.nexedi.com/nexedi/slapos.recipe.template/merge_requests/9 import zc.buildout.buildout # XXX workaround for https://lab.nexedi.com/nexedi/slapos.recipe.template/merge_requests/9
from slapos.recipe.template import jinja2_template from slapos.recipe.template import jinja2_template
import json, os, glob import json, copy, sys, os, pprint, shutil
sys.path.insert(0, './ru')
import xbuildout
B = xbuildout.encode
# j2render renders config/<src> into config/out/<out> with provided json parameters. # j2render renders config/<src> into config/out/<out> with provided json parameters.
def j2render(src, out, jcfg): def j2render(src, out, jcfg):
src = 'config/{}'.format(src)
out = 'config/out/{}'.format(out)
ctx = json.loads(jcfg) ctx = json.loads(jcfg)
assert '_standalone' not in ctx assert '_standalone' not in ctx
ctx['_standalone'] = True ctx['_standalone'] = True
ctx.setdefault('ors', False)
textctx = '' textctx = ''
for k, v in ctx.items(): for k, v in ctx.items():
textctx += 'json %s %s\n' % (k, json.dumps(v)) textctx += 'json %s %s\n' % (k, json.dumps(v))
textctx += 'import xbuildout xbuildout\n'
textctx += 'import json_module json\n' textctx += 'import json_module json\n'
textctx += 'import nrarfcn_module nrarfcn\n'
textctx += 'import xearfcn_module xlte.earfcn\n'
textctx += 'import xnrarfcn_module xlte.nrarfcn\n'
buildout = None # stub buildout = None # stub
r = jinja2_template.Recipe(buildout, "recipe", { r = jinja2_template.Recipe(buildout, "recipe", {
'extensions': 'jinja2.ext.do', 'extensions': 'jinja2.ext.do',
'url': 'config/{}'.format(src), 'url': src,
'output': 'config/out/{}'.format(out), 'output': out,
'context': textctx, 'context': textctx,
'import-list': ''' 'import-list': '''
rawfile slaplte.jinja2 slaplte.jinja2''', rawfile slaplte.jinja2 slaplte.jinja2''',
...@@ -35,106 +48,588 @@ def j2render(src, out, jcfg): ...@@ -35,106 +48,588 @@ def j2render(src, out, jcfg):
return f.read() return f.read()
r._read = _read r._read = _read
with open('config/out/{}'.format(out), 'w+') as f: # for template debugging
r.context.update({
'print': lambda *argv: print(*argv, file=sys.stderr),
'pprint': lambda obj: pprint.pprint(obj, sys.stderr),
})
os.makedirs(os.path.dirname(out), exist_ok=True)
with open(out, 'w+') as f:
f.write(r._render().decode()) f.write(r._render().decode())
def do(src, out, rat, slapparameter_dict): # Instance simulates configuration for an instance on SlapOS Master.
assert rat in ('lte', 'nr') class Instance:
jdo_lte = json.dumps(rat == 'lte') def __init__(self, slap_software_type):
jdo_nr = json.dumps(rat == 'nr') self.shared_instance_list = []
jslapparameter_dict = json.dumps(slapparameter_dict) self.slap_software_type = slap_software_type
json_params_empty = """{
"rf_mode": 'fdd', # ishared appends new shared instance with specified configuration to .shared_instance_list .
"slap_configuration": { def ishared(self, slave_reference, cfg):
ishared = {
# see comments in jref_of_shared about where and how slapproxy and
# slapos master put partition_reference of a shared instance.
'slave_title': '_%s' % slave_reference,
'slave_reference': 'SOFTINST-%03d' % (len(self.shared_instance_list)+1),
'slap_software_type': self.slap_software_type,
'_': json.dumps(cfg)
}
self.shared_instance_list.append(ishared)
return ishared
# py version of jref_of_shared (simplified).
def ref_of_shared(ishared):
ref = ishared['slave_title']
ref = ref.removeprefix('_')
return ref
# ---- eNB ----
# 3 cells sharing SDR-based RU consisting of 2 SDR boards (4tx + 4rx ports max)
# RU definition is embedded into cell for simplicity of management
def iRU1_SDR_tLTE2_tNR(ienb):
RU = {
'ru_type': 'sdr',
'ru_link_type': 'sdr',
'sdr_dev_list': [0, 1],
'n_antenna_dl': 4,
'n_antenna_ul': 2,
'tx_gain': 51,
'rx_gain': 52,
}
ienb.ishared('CELL_a', {
'cell_type': 'lte',
'cell_kind': 'enb',
'rf_mode': 'tdd',
'bandwidth': 5,
'dl_earfcn': 38050, # 2600 MHz
'pci': 1,
'cell_id': '0x01',
'tac': '0x1234',
'ru': RU, # RU definition embedded into CELL
})
ienb.ishared('CELL_b', {
'cell_type': 'lte',
'cell_kind': 'enb',
'rf_mode': 'tdd',
'bandwidth': 5,
'dl_earfcn': 38100, # 2605 MHz
'pci': 2,
'cell_id': '0x02',
'tac': '0x1234',
'ru': { # CELL_b shares RU with CELL_a referring to it via cell
'ru_type': 'ruincell_ref',
'ruincell_ref': 'CELL_a'
}
})
ienb.ishared('CELL_c', {
'cell_type': 'nr',
'cell_kind': 'enb',
'rf_mode': 'tdd',
'bandwidth': 10,
'dl_nr_arfcn': 523020, # 2615.1 MHz
'nr_band': 41,
'pci': 3,
'cell_id': '0x03',
'tac': '0x1234',
'ru': {
'ru_type': 'ruincell_ref', # CELL_c shares RU with CELL_a and CELL_b
'ruincell_ref': 'CELL_b' # referring to RU via CELL_b -> CELL_a
}
})
# LTE + NR cells using 2 RU each consisting of SDR.
# here we instantiate RUs separately since embedding RU into a cell is demonstrated by CELL_a above
#
# NOTE: if we would want to share the RU by LTE/tdd and NR/tdd cells, we would
# need to bring their TDD configuration to match each other exactly.
def iRU2_SDR_tLTE_tNR(ienb):
RU1 = {
'ru_type': 'sdr',
'ru_link_type': 'sdr',
'sdr_dev_list': [1],
'n_antenna_dl': 2,
'n_antenna_ul': 1,
'tx_gain': 51,
'rx_gain': 52,
'txrx_active': 'ACTIVE',
}
RU2 = copy.deepcopy(RU1)
RU2['sdr_dev_list'] = [2]
ienb.ishared('RU1', RU1)
ienb.ishared('RU2', RU2)
ienb.ishared('CELL_a', {
'cell_type': 'lte',
'cell_kind': 'enb',
'rf_mode': 'tdd',
'bandwidth': 5,
'dl_earfcn': 38050, # 2600 MHz
'pci': 1,
'cell_id': '0x01',
'tac': '0x1234',
'ru': { # CELL_a links to RU1 by its reference
'ru_type': 'ru_ref',
'ru_ref': 'RU1'
}
})
ienb.ishared('CELL_b', {
'cell_type': 'nr',
'cell_kind': 'enb',
'rf_mode': 'tdd',
'bandwidth': 10,
'dl_nr_arfcn': 523020, # 2615.1 MHz
'nr_band': 41,
'pci': 2,
'cell_id': '0x02',
'tac': '0x1234',
'ru': {
'ru_type': 'ru_ref',
'ru_ref': 'RU2'
}
})
# LTE + NR cells that use CPRI-based Lopcomm radio units
def iRU2_LOPCOMM_fLTE_fNR(ienb):
RU1 = {
'ru_type': 'lopcomm',
'ru_link_type': 'cpri',
'mac_addr': '00:00:00:00:00:01',
'cpri_link': {
'sdr_dev': 2,
'sfp_port': 0,
'mult': 8,
'mapping': 'standard',
'rx_delay': 10,
'tx_delay': 11,
'tx_dbm': 50
}, },
"directory": { 'n_antenna_dl': 2,
'n_antenna_ul': 1,
'tx_gain': -21,
'rx_gain': -22,
}
RU2 = copy.deepcopy(RU1)
RU2['mac_addr'] = '00:00:00:00:00:02'
RU2['cpri_link']['sfp_port'] = 1
RU2['tx_gain'] += 10
RU2['rx_gain'] += 10
ienb.ishared('RU1', RU1)
ienb.ishared('RU2', RU2)
ienb.ishared('CELL_a', {
'cell_type': 'lte',
'cell_kind': 'enb',
'rf_mode': 'fdd',
'bandwidth': 5,
'dl_earfcn': 3350, # 2680 MHz
'pci': 21,
'cell_id': '0x21',
'tac': '0x1234',
'ru': {
'ru_type': 'ru_ref',
'ru_ref': 'RU1'
}
})
ienb.ishared('CELL_b', {
'cell_type': 'nr',
'cell_kind': 'enb',
'rf_mode': 'fdd',
'bandwidth': 5,
'dl_nr_arfcn': 537200, # 2686 MHz
'nr_band': 7,
'pci': 22,
'cell_id': '0x22',
'tac': '0x1234',
'ru': {
'ru_type': 'ru_ref',
'ru_ref': 'RU2'
}
})
# ---- for tests ----
# 2 FDD cells working via shared SDR board
def iRU1_SDR1_fLTE2(ienb):
RU = {
'ru_type': 'sdr',
'ru_link_type': 'sdr',
'sdr_dev_list': [1],
'n_antenna_dl': 1,
'n_antenna_ul': 1,
'tx_gain': 67,
'rx_gain': 61,
}
ienb.ishared('CELL_a', {
'cell_type': 'lte',
'cell_kind': 'enb',
'rf_mode': 'fdd',
'bandwidth': 5,
'dl_earfcn': 3350, # 2680 MHz (Band 7)
'pci': 1,
'cell_id': '0x01',
'tac': '0x1234',
'ru': RU,
})
ienb.ishared('CELL_b', {
'cell_type': 'lte',
'cell_kind': 'enb',
'rf_mode': 'fdd',
'bandwidth': 5,
'dl_earfcn': 3050, # 2650 MHz (Band 7)
'pci': 1,
'cell_id': '0x02',
'tac': '0x1234',
'ru': {
'ru_type': 'ruincell_ref',
'ruincell_ref': 'CELL_a'
}
})
def iRU2_LOPCOMM_fLTE2(ienb):
# supports: 2110 - 2170 MHz
RU_0002 = {
'ru_type': 'lopcomm',
'ru_link_type': 'cpri',
'mac_addr': '00:00:00:00:00:01',
'cpri_link': {
'sdr_dev': 0,
'sfp_port': 0,
'mult': 8,
'mapping': 'hw',
'rx_delay': 25.11,
'tx_delay': 14.71,
'tx_dbm': 63
}, },
"slapparameter_dict": %(jslapparameter_dict)s 'n_antenna_dl': 1,
}""" 'n_antenna_ul': 1,
json_params = """{ 'tx_gain': 0,
"rf_mode": "tdd", 'rx_gain': 0,
"do_lte": %(jdo_lte)s, }
"do_nr": %(jdo_nr)s,
"trx": "sdr", # supports: 2110 - 2170 MHz
"bbu": "ors", RU_0004 = copy.deepcopy(RU_0002)
"ru_type": "ors", RU_0004['mac_addr'] = '00:00:00:00:00:04'
RU_0004['cpri_link']['sfp_port'] = 1
if 1:
ienb.ishared('RU_0002', RU_0002)
ienb.ishared('CELL2', {
'cell_type': 'lte',
'cell_kind': 'enb',
'rf_mode': 'fdd',
'bandwidth': 20,
'dl_earfcn': 100, # 2120 MHz @ B1
'pci': 21,
'cell_id': '0x21',
'tac': '0x1234',
'ru': {
'ru_type': 'ru_ref',
'ru_ref': 'RU_0002'
}
})
if 1:
ienb.ishared('RU_0004', RU_0004)
ienb.ishared('CELL4', {
'cell_type': 'lte',
'cell_kind': 'enb',
'rf_mode': 'fdd',
'bandwidth': 20,
'dl_earfcn': 500, # 2160 MHz @ B1
'pci': 22,
'cell_id': '0x22',
'tac': '0x1234',
'ru': {
'ru_type': 'ru_ref',
'ru_ref': 'RU_0004'
}
})
# ORS_eNB and ORS_gNB mimic what instance-ors-enb.jinja2.cfg does.
ORS_ru = {
'ru_type': 'sdr',
'ru_link_type': 'sdr',
'sdr_dev_list': [0],
'n_antenna_dl': 2,
'n_antenna_ul': 2,
'tx_gain': 62,
'rx_gain': 43,
}
ORS_json = """
"ors": {"one-watt": true}, "ors": {"one-watt": true},
"earfcn": 36100, """
"nr_arfcn": 380000, def ORS_enb(ienb):
"nr_band": 39, ienb.ishared('RU', ORS_ru)
"tx_gain": 62, ienb.ishared('CELL', {
"rx_gain": 43, 'cell_type': 'lte',
"sib23_file": "sib", 'cell_kind': 'enb',
"drb_file": "drb", 'rf_mode': 'tdd',
"slap_configuration": { 'dl_earfcn': 36100,
"tap-name": "slaptap9", 'bandwidth': 10,
"configuration.default_lte_bandwidth": "10 MHz", 'tac': '0x0001',
"configuration.default_lte_imsi": "001010123456789", 'root_sequence_index': 204,
"configuration.default_lte_k": "00112233445566778899aabbccddeeff", 'pci': 1,
"configuration.default_lte_inactivity_timer": 10000, 'cell_id': '0x01',
"configuration.default_nr_bandwidth": 40, "tdd_ul_dl_config": "[Configuration 6] 5ms 5UL 3DL (maximum uplink)",
"configuration.default_nr_imsi": "001010123456789", 'inactivity_timer': 10000,
"configuration.default_nr_k": "00112233445566778899aabbccddeeff", 'ru': {
"configuration.default_nr_ssb_pos_bitmap": "10000000", 'ru_type': 'ru_ref',
"configuration.default_n_antenna_dl": 2, 'ru_ref': 'RU',
"configuration.default_n_antenna_ul": 2,
"configuration.default_nr_inactivity_timer": 10000,
"configuration.com_ws_port": 9001,
"configuration.com_addr": "127.0.1.2",
"configuration.amf_addr": "127.0.1.100",
"configuration.mme_addr": "127.0.1.100",
"configuration.gtp_addr": "127.0.1.1"
},
"directory": {
"log": "log",
"etc": "etc",
"var": "var"
},
"pub_info": {
"rue_bind_addr": "::1",
"com_addr": "[::1]:9002"
}, },
"slapparameter_dict": %(jslapparameter_dict)s })
}""" return {'out': 'ors/enb', 'jextra': ORS_json, 'want_nr': False}
j2render(src, out, json_params % locals()) def ORS_gnb(ienb):
ienb.ishared('RU', ORS_ru)
ienb.ishared('CELL', {
'cell_type': 'nr',
'cell_kind': 'enb',
'rf_mode': 'tdd',
'dl_nr_arfcn': 380000,
'nr_band': 39,
'bandwidth': 40,
'ssb_pos_bitmap': "10000000",
'root_sequence_index': 1,
'pci': 500,
'cell_id': '0x01',
"tdd_ul_dl_config": "5ms 8UL 1DL 2/10 (maximum uplink)",
'inactivity_timer': 10000,
'ru': {
'ru_type': 'ru_ref',
'ru_ref': 'RU',
},
})
return {'out': 'ors/gnb', 'jextra': ORS_json, 'want_lte': False}
def do_enb(): def do_enb():
peer_lte = { for f in (iRU1_SDR_tLTE2_tNR,
'cell_id': '0x12345', iRU2_SDR_tLTE_tNR,
iRU2_LOPCOMM_fLTE_fNR,
iRU1_SDR1_fLTE2,
iRU2_LOPCOMM_fLTE2,
ORS_enb,
ORS_gnb):
_do_enb_with(f)
def _do_enb_with(iru_icell_func):
ienb = Instance('enb')
opt = iru_icell_func(ienb) or {}
out = opt.get('out', 'enb/%s' % iru_icell_func.__name__)
want_lte = opt.get('want_lte', True)
want_nr = opt.get('want_nr', True)
# add 4 peer nodes
if want_lte:
ienb.ishared('PEER11', {
'peer_type': 'lte',
'x2_addr': '44.1.1.1',
})
ienb.ishared('PEER12', {
'peer_type': 'lte',
'x2_addr': '44.1.1.2',
})
if want_nr:
ienb.ishared('PEER21', {
'peer_type': 'nr',
'xn_addr': '55.1.1.1',
})
ienb.ishared('PEER22', {
'peer_type': 'nr',
'xn_addr': '55.1.1.2',
})
# add 2 peer cells
if want_lte:
ienb.ishared('PEERCELL1', {
'cell_type': 'lte',
'cell_kind': 'enb_peer',
'e_cell_id': '0x12345',
'pci': 35, 'pci': 35,
'dl_earfcn': 700, 'dl_earfcn': 700,
'tac': 123, 'tac': 123,
} })
peer_nr = { if want_nr:
ienb.ishared('PEERCELL2', {
'cell_type': 'nr',
'cell_kind': 'enb_peer',
'nr_cell_id': '0x77712', 'nr_cell_id': '0x77712',
'gnb_id_bits': 22, 'gnb_id_bits': 22,
'dl_nr_arfcn': 520000, 'dl_nr_arfcn': 520000,
'nr_band': 38, 'nr_band': 38,
'pci': 75, 'pci': 75,
'tac': 321, 'tac': 321,
})
jshared_instance_list = json.dumps(ienb.shared_instance_list)
jextra = opt.get('jextra', '')
json_params = """{
%(jextra)s
"sib23_file": "sib2_3.asn",
"slap_configuration": {
"tap-name": "slaptap9",
"slap-computer-partition-id": "slappart9",
"slave-instance-list": %(jshared_instance_list)s
},
"directory": {
"log": "log",
"etc": "etc",
"var": "var"
},
"slapparameter_dict": {
"enb_id": "0x1A2D0",
"gnb_id": "0x12345",
"gnb_id_bits": 28,
"com_ws_port": 9001,
"com_addr": "127.0.1.2",
"gtp_addr": "127.0.1.1",
"mme_list": {"1": {"mme_addr": "127.0.1.100"}},
"amf_list": {"1": {"amf_addr": "127.0.1.100"}},
"plmn_list": {"1": {"plmn": "00101"}},
"plmn_list_5g": {"1": {"plmn": "00101", "tac": 100}},
"nssai": {"1": {"sst": 1}}
} }
}""" % locals()
do('enb.jinja2.cfg', 'enb.cfg', 'lte', { j2render('enb.jinja2.cfg', '%s/enb.cfg' % out, json_params)
"tdd_ul_dl_config": "[Configuration 6] 5ms 5UL 3DL (maximum uplink)",
"ncell_list": {'1': peer_lte}, # drb.cfg + sib.asn for all cells
}) iru_dict = {}
do('enb.jinja2.cfg', 'gnb.cfg', 'nr', { icell_dict = {}
"tdd_ul_dl_config": "5ms 8UL 1DL 2/10 (maximum uplink)", ipeer_dict = {}
"ncell_list": {'1': peer_nr}, ipeercell_dict = {}
for ishared in ienb.shared_instance_list:
ref = ref_of_shared(ishared)
_ = json.loads(ishared['_'])
ishared['_'] = _
if 'ru_type' in _:
iru_dict[ref] = ishared
elif 'cell_type' in _ and _.get('cell_kind') in {'enb', 'enb_peer'}:
idict = {'enb': icell_dict, 'enb_peer': ipeercell_dict} [_['cell_kind']]
idict[ref] = ishared
elif 'peer_type' in _:
ipeer_dict[ref] = ishared
else:
raise AssertionError('enb: unknown shared instance %r' % (ishared,))
def ru_of_cell(icell): # -> (ru_ref, ru)
cell_ref = ref_of_shared(icell)
ru = icell['_']['ru']
if ru['ru_type'] == 'ru_ref':
ru_ref = ru['ru_ref']
return ru_ref, iru_dict[ru_ref]
elif ru['ru_type'] == 'ruincell_ref':
return ru_of_cell(icell_dict[ru['ruincell_ref']])
else:
return ('_%s_ru' % cell_ref), ru # embedded ru definition
for cell_ref, icell in icell_dict.items():
ru_ref, ru = ru_of_cell(icell)
cell = icell['_']
jctx = json.dumps({
'cell_ref': cell_ref,
'cell': cell,
'ru_ref': ru_ref,
'ru': ru,
}) })
j2render('drb_%s.jinja2.cfg' % cell['cell_type'],
'%s/%s-drb.cfg' % (out, B(cell_ref)),
jctx)
j2render('sib23.jinja2.asn',
'%s/%s-sib23.asn' % (out, B(cell_ref)),
jctx)
# ---- UE ----
def do_ue(): def do_ue():
do('ue.jinja2.cfg', 'ue-lte.cfg', 'lte', {'rue_addr': 'host1'}) iue = Instance('ue')
do('ue.jinja2.cfg', 'ue-nr.cfg', 'nr', {'rue_addr': 'host2'}) iue.ishared('UCELL1', {
'cell_type': 'lte',
'cell_kind': 'ue',
'rf_mode': 'tdd',
'bandwidth': 5,
'dl_earfcn': 38050, # 2600 MHz
'ru': {
'ru_type': 'sdr',
'ru_link_type': 'sdr',
'sdr_dev_list': [0],
'n_antenna_dl': 2,
'n_antenna_ul': 1,
'tx_gain': 41,
'rx_gain': 42,
}
})
iue.ishared('UCELL2', {
'cell_type': 'nr',
'cell_kind': 'ue',
'rf_mode': 'fdd',
'bandwidth': 5,
'dl_nr_arfcn': 537200, # 2686 MHz
'nr_band': 7,
'ru': { # NOTE contrary to eNB UEsim cannot share one RU in between several cells
'ru_type': 'sdr',
'ru_link_type': 'sdr',
'sdr_dev_list': [2],
'n_antenna_dl': 2,
'n_antenna_ul': 2,
'tx_gain': 31,
'rx_gain': 32,
}
})
iue.ishared('UE1', {
'ue_type': 'lte',
'rue_addr': 'host1'
})
iue.ishared('UE2', {
'ue_type': 'nr',
'rue_addr': 'host2'
})
jshared_instance_list = json.dumps(iue.shared_instance_list)
json_params = """{
"slap_configuration": {
"tap-name": "slaptap9",
"slap-computer-partition-id": "slappart9",
"slave-instance-list": %(jshared_instance_list)s
},
"pub_info": {
"rue_bind_addr": "::1",
"com_addr": "[::1]:9002"
},
"directory": {
"log": "log",
"etc": "etc",
"var": "var"
},
"slapparameter_dict": {
}
}""" % locals()
j2render('ue.jinja2.cfg', 'ue.cfg', json_params)
def main(): def main():
os.makedirs('config/out', exist_ok=True) if os.path.exists('config/out'):
for f in glob.glob('config/out/*'): shutil.rmtree('config/out')
os.remove(f)
do_enb() do_enb()
do_ue() do_ue()
......
# This file was generated using a jinja2 template and the render-templates script, don't modify directly.
[buildout]
extends =
software-base.cfg
[default-params]
default-lte-bandwidth = 20 MHz
default-lte-inactivity-timer = 10000
default-lte-imsi = 001010123456789
default-lte-k = 00112233445566778899aabbccddeeff
default-nr-bandwidth = 40
default-nr-ssb-pos-bitmap = 10000000
default-nr-inactivity-timer = 10000
default-nr-imsi = 001010123456789
default-nr-k = 00112233445566778899aabbccddeeff
default-n-antenna-dl = 2
default-n-antenna-ul = 2
[rf-mode]
software-name = fdd-lopcomm
rf-mode = fdd
trx = cpri
bbu = server
ru = lopcomm
{
"name": "ORS Amarisoft",
"description": "4G and 5G amarisoft stack for ORS",
"serialisation": "json-in-xml",
"software-type": {
"ue-lte": {
"title": "UE-LTE",
"description": "UE LTE Configuration",
"software-type": "ue-lte",
"request": "instance-fdd-lopcomm-ue-lte-input-schema.json",
"response": "instance-fdd-lopcomm-ue-lte-schema.json",
"index": 4
},
"ue-nr": {
"title": "UE-NR",
"description": "UE NR Configuration",
"software-type": "ue-nr",
"request": "instance-fdd-lopcomm-ue-nr-input-schema.json",
"response": "instance-fdd-lopcomm-ue-nr-schema.json",
"index": 5
},
"enb": {
"title": "eNB",
"software-type": "enb",
"description": "eNodeB Configuration",
"request": "instance-fdd-lopcomm-enb-input-schema.json",
"response": "instance-fdd-lopcomm-enb-schema.json",
"index": 0
},
"gnb": {
"title": "gNB",
"software-type": "gnb",
"description": "gNodeB Configuration",
"request": "instance-fdd-lopcomm-gnb-input-schema.json",
"response": "instance-fdd-lopcomm-gnb-schema.json",
"index": 1
},
"core-network": {
"title": "Core Network",
"software-type": "core-network",
"description": "Core Network Configuration",
"request": "instance-core-network-input-schema.json",
"response": "instance-core-network-schema.json",
"index": 2
},
"core-network-slave": {
"title": "Core Network Sim Card",
"description": "Core Network Sim Card Configuration",
"software-type": "core-network",
"request": "instance-core-network-slave-input-schema.json",
"response": "instance-core-network-slave-schema.json",
"shared": true,
"index": 3
}
}
}
# This file was generated using a jinja2 template and the render-templates script, don't modify directly.
[buildout]
extends =
software-ors.cfg
[default-params]
default-lte-bandwidth = 20 MHz
default-lte-inactivity-timer = 10000
default-lte-imsi = 001010123456789
default-lte-k = 00112233445566778899aabbccddeeff
default-nr-bandwidth = 40
default-nr-ssb-pos-bitmap = 10000000
default-nr-inactivity-timer = 10000
default-nr-imsi = 001010123456789
default-nr-k = 00112233445566778899aabbccddeeff
default-n-antenna-dl = 2
default-n-antenna-ul = 2
[rf-mode]
software-name = fdd-ors
rf-mode = fdd
trx = sdr
bbu = ors
ru = ors
{
"name": "ORS Amarisoft",
"description": "4G and 5G amarisoft stack for ORS",
"serialisation": "json-in-xml",
"software-type": {
"enb": {
"title": "eNB",
"software-type": "enb",
"description": "eNodeB Configuration",
"request": "instance-fdd-ors-enb-input-schema.json",
"response": "instance-fdd-ors-enb-schema.json",
"index": 0
},
"gnb": {
"title": "gNB",
"software-type": "gnb",
"description": "gNodeB Configuration",
"request": "instance-fdd-ors-gnb-input-schema.json",
"response": "instance-fdd-ors-gnb-schema.json",
"index": 1
},
"core-network": {
"title": "Core Network",
"software-type": "core-network",
"description": "Core Network Configuration",
"request": "instance-core-network-input-schema.json",
"response": "instance-core-network-schema.json",
"index": 2
},
"core-network-slave": {
"title": "Core Network Sim Card",
"description": "Core Network Sim Card Configuration",
"software-type": "core-network",
"request": "instance-core-network-slave-input-schema.json",
"response": "instance-core-network-slave-schema.json",
"shared": true,
"index": 3
}
}
}
# This file was generated using a jinja2 template and the render-templates script, don't modify directly.
[buildout]
extends =
software-base.cfg
[default-params]
default-lte-bandwidth = 20 MHz
default-lte-inactivity-timer = 10000
default-lte-imsi = 001010123456789
default-lte-k = 00112233445566778899aabbccddeeff
default-nr-bandwidth = 40
default-nr-ssb-pos-bitmap = 10000000
default-nr-inactivity-timer = 10000
default-nr-imsi = 001010123456789
default-nr-k = 00112233445566778899aabbccddeeff
default-n-antenna-dl = 2
default-n-antenna-ul = 2
[rf-mode]
software-name = fdd
rf-mode = fdd
trx = sdr
bbu = server
ru = any
{
"name": "ORS Amarisoft",
"description": "4G and 5G amarisoft stack for ORS",
"serialisation": "json-in-xml",
"software-type": {
"ue-lte": {
"title": "UE-LTE",
"description": "UE LTE Configuration",
"software-type": "ue-lte",
"request": "instance-fdd-ue-lte-input-schema.json",
"response": "instance-fdd-ue-lte-schema.json",
"index": 4
},
"ue-nr": {
"title": "UE-NR",
"description": "UE NR Configuration",
"software-type": "ue-nr",
"request": "instance-fdd-ue-nr-input-schema.json",
"response": "instance-fdd-ue-nr-schema.json",
"index": 5
},
"enb": {
"title": "eNB",
"software-type": "enb",
"description": "eNodeB Configuration",
"request": "instance-fdd-enb-input-schema.json",
"response": "instance-fdd-enb-schema.json",
"index": 0
},
"gnb": {
"title": "gNB",
"software-type": "gnb",
"description": "gNodeB Configuration",
"request": "instance-fdd-gnb-input-schema.json",
"response": "instance-fdd-gnb-schema.json",
"index": 1
},
"core-network": {
"title": "Core Network",
"software-type": "core-network",
"description": "Core Network Configuration",
"request": "instance-core-network-input-schema.json",
"response": "instance-core-network-schema.json",
"index": 2
},
"core-network-slave": {
"title": "Core Network Sim Card",
"description": "Core Network Sim Card Configuration",
"software-type": "core-network",
"request": "instance-core-network-slave-input-schema.json",
"response": "instance-core-network-slave-schema.json",
"shared": true,
"index": 3
}
}
}
# software for Open Radio Station. # software for Open Radio Station.
# #
# It is a wrapper around base software which adds ORS-specific features. # It is a wrapper around generic software which adds ORS-specific features and
# translates simplified enb/gnb ORS-specific configuration schema to generic enb.
#
# ORS intended usage is small private networks.
[buildout] [buildout]
extends = extends =
software-base.cfg software.cfg
parts += parts +=
template-ors template-ors
......
...@@ -3,22 +3,21 @@ ...@@ -3,22 +3,21 @@
"description": "4G and 5G amarisoft stack for ORS", "description": "4G and 5G amarisoft stack for ORS",
"serialisation": "json-in-xml", "serialisation": "json-in-xml",
"software-type": { "software-type": {
"enb": { "enb": {
"title": "eNB", "title": "eNB",
"software-type": "enb", "software-type": "enb",
"description": "eNodeB Configuration", "description": "eNodeB Configuration",
"request": "instance-tdd-ors-enb-input-schema.json", "request": "instance-ors-enb-input-schema.json",
"response": "instance-tdd-ors-enb-schema.json", "response": "instance-ors-enb-schema.json",
"index": 0 "index": 1
}, },
"gnb": { "gnb": {
"title": "gNB", "title": "gNB",
"software-type": "gnb", "software-type": "gnb",
"description": "gNodeB Configuration", "description": "gNodeB Configuration",
"request": "instance-tdd-ors-gnb-input-schema.json", "request": "instance-ors-gnb-input-schema.json",
"response": "instance-tdd-ors-gnb-schema.json", "response": "instance-ors-gnb-schema.json",
"index": 1 "index": 2
}, },
"core-network": { "core-network": {
"title": "Core Network", "title": "Core Network",
...@@ -26,16 +25,16 @@ ...@@ -26,16 +25,16 @@
"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": 3
}, },
"core-network-slave": { "core-network-slave": {
"title": "Core Network Sim Card", "title": "Core Network Sim Card",
"description": "Core Network Sim Card Configuration", "description": "Core Network Sim Card Configuration",
"software-type": "core-network", "software-type": "core-network",
"request": "instance-core-network-slave-input-schema.json", "request": "sim/input-schema.json",
"response": "instance-core-network-slave-schema.json", "response": "sim/schema.json",
"shared": true, "shared": true,
"index": 3 "index": 4
} }
} }
} }
# This file was generated using a jinja2 template and the render-templates script, don't modify directly.
[buildout]
extends =
software-base.cfg
[default-params]
default-lte-bandwidth = 20 MHz
default-lte-inactivity-timer = 10000
default-lte-imsi = 001010123456789
default-lte-k = 00112233445566778899aabbccddeeff
default-nr-bandwidth = 40
default-nr-ssb-pos-bitmap = 10000000
default-nr-inactivity-timer = 10000
default-nr-imsi = 001010123456789
default-nr-k = 00112233445566778899aabbccddeeff
default-n-antenna-dl = 2
default-n-antenna-ul = 2
[rf-mode]
software-name = tdd-m2ru
rf-mode = tdd
trx = cpri
bbu = server
ru = m2ru
{
"name": "ORS Amarisoft",
"description": "4G and 5G amarisoft stack for ORS",
"serialisation": "json-in-xml",
"software-type": {
"ue-lte": {
"title": "UE-LTE",
"description": "UE LTE Configuration",
"software-type": "ue-lte",
"request": "instance-tdd-m2ru-ue-lte-input-schema.json",
"response": "instance-tdd-m2ru-ue-lte-schema.json",
"index": 4
},
"ue-nr": {
"title": "UE-NR",
"description": "UE NR Configuration",
"software-type": "ue-nr",
"request": "instance-tdd-m2ru-ue-nr-input-schema.json",
"response": "instance-tdd-m2ru-ue-nr-schema.json",
"index": 5
},
"enb": {
"title": "eNB",
"software-type": "enb",
"description": "eNodeB Configuration",
"request": "instance-tdd-m2ru-enb-input-schema.json",
"response": "instance-tdd-m2ru-enb-schema.json",
"index": 0
},
"gnb": {
"title": "gNB",
"software-type": "gnb",
"description": "gNodeB Configuration",
"request": "instance-tdd-m2ru-gnb-input-schema.json",
"response": "instance-tdd-m2ru-gnb-schema.json",
"index": 1
},
"core-network": {
"title": "Core Network",
"software-type": "core-network",
"description": "Core Network Configuration",
"request": "instance-core-network-input-schema.json",
"response": "instance-core-network-schema.json",
"index": 2
},
"core-network-slave": {
"title": "Core Network Sim Card",
"description": "Core Network Sim Card Configuration",
"software-type": "core-network",
"request": "instance-core-network-slave-input-schema.json",
"response": "instance-core-network-slave-schema.json",
"shared": true,
"index": 3
}
}
}
# This file was generated using a jinja2 template and the render-templates script, don't modify directly. # software-tdd-ors.cfg is backward compatibility proxy to software-ors.cfg
# because most existing ORS deployements were instantiated via
# software-tdd-ors.cfg before rf_mode became runtime parameter.
#
# TODO remove it once ORS deployments are migrated to software-ors.cfg
[buildout] [buildout]
extends = extends =
software-ors.cfg software-ors.cfg
[default-params]
default-lte-bandwidth = 20 MHz
default-lte-inactivity-timer = 10000
default-lte-imsi = 001010123456789
default-lte-k = 00112233445566778899aabbccddeeff
default-nr-bandwidth = 40
default-nr-ssb-pos-bitmap = 10000000
default-nr-inactivity-timer = 10000
default-nr-imsi = 001010123456789
default-nr-k = 00112233445566778899aabbccddeeff
default-n-antenna-dl = 2
default-n-antenna-ul = 2
[rf-mode]
software-name = tdd-ors
rf-mode = tdd
trx = sdr
bbu = ors
ru = ors
# This file was generated using a jinja2 template and the render-templates script, don't modify directly.
[buildout]
extends =
software-base.cfg
[default-params]
default-lte-bandwidth = 20 MHz
default-lte-inactivity-timer = 10000
default-lte-imsi = 001010123456789
default-lte-k = 00112233445566778899aabbccddeeff
default-nr-bandwidth = 40
default-nr-ssb-pos-bitmap = 10000000
default-nr-inactivity-timer = 10000
default-nr-imsi = 001010123456789
default-nr-k = 00112233445566778899aabbccddeeff
default-n-antenna-dl = 2
default-n-antenna-ul = 2
[rf-mode]
software-name = tdd
rf-mode = tdd
trx = sdr
bbu = server
ru = any
{
"name": "ORS Amarisoft",
"description": "4G and 5G amarisoft stack for ORS",
"serialisation": "json-in-xml",
"software-type": {
"ue-lte": {
"title": "UE-LTE",
"description": "UE LTE Configuration",
"software-type": "ue-lte",
"request": "instance-tdd-ue-lte-input-schema.json",
"response": "instance-tdd-ue-lte-schema.json",
"index": 4
},
"ue-nr": {
"title": "UE-NR",
"description": "UE NR Configuration",
"software-type": "ue-nr",
"request": "instance-tdd-ue-nr-input-schema.json",
"response": "instance-tdd-ue-nr-schema.json",
"index": 5
},
"enb": {
"title": "eNB",
"software-type": "enb",
"description": "eNodeB Configuration",
"request": "instance-tdd-enb-input-schema.json",
"response": "instance-tdd-enb-schema.json",
"index": 0
},
"gnb": {
"title": "gNB",
"software-type": "gnb",
"description": "gNodeB Configuration",
"request": "instance-tdd-gnb-input-schema.json",
"response": "instance-tdd-gnb-schema.json",
"index": 1
},
"core-network": {
"title": "Core Network",
"software-type": "core-network",
"description": "Core Network Configuration",
"request": "instance-core-network-input-schema.json",
"response": "instance-core-network-schema.json",
"index": 2
},
"core-network-slave": {
"title": "Core Network Sim Card",
"description": "Core Network Sim Card Configuration",
"software-type": "core-network",
"request": "instance-core-network-slave-input-schema.json",
"response": "instance-core-network-slave-schema.json",
"shared": true,
"index": 3
}
}
}
# generic software for Amarisoft 4G/5G stack.
#
# Its intended usage is small-to-medium networks.
[buildout] [buildout]
extends = extends =
buildout.hash.cfg buildout.hash.cfg
...@@ -152,6 +156,7 @@ eggs = ...@@ -152,6 +156,7 @@ eggs =
xmltodict xmltodict
ncclient ncclient
${lxml-python:egg} ${lxml-python:egg}
nrarfcn
netifaces netifaces
netaddr netaddr
interpreter = pythonwitheggs interpreter = pythonwitheggs
...@@ -159,7 +164,7 @@ interpreter = pythonwitheggs ...@@ -159,7 +164,7 @@ interpreter = pythonwitheggs
[xlte-repository] [xlte-repository]
recipe = slapos.recipe.build:gitclone recipe = slapos.recipe.build:gitclone
repository = https://lab.nexedi.com/kirr/xlte.git repository = https://lab.nexedi.com/kirr/xlte.git
revision = e716ab51 revision = 8e606c64
git-executable = ${git:location}/bin/git git-executable = ${git:location}/bin/git
[xlte] [xlte]
...@@ -188,3 +193,4 @@ exe = ${dnsmasq:location}/sbin/dnsmasq ...@@ -188,3 +193,4 @@ exe = ${dnsmasq:location}/sbin/dnsmasq
websocket-client = 1.4.2 websocket-client = 1.4.2
ncclient = 0.6.13 ncclient = 0.6.13
xmltodict = 0.13.0 xmltodict = 0.13.0
nrarfcn = 2.4.0:whl
{
"name": "Amarisoft stack",
"description": "4G and 5G amarisoft stack",
"serialisation": "json-in-xml",
"software-type": {
"enb": {
"title": "eNB/gNB",
"software-type": "enb",
"description": "eNodeB/gNodeB Configuration",
"request": "instance-enb-input-schema.json",
"response": "instance-enb-schema.json",
"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": {
"title": "Core Network",
"software-type": "core-network",
"description": "Core Network Configuration",
"request": "instance-core-network-input-schema.json",
"response": "instance-core-network-schema.json",
"index": 6
},
"core-network-slave": {
"title": "→ Core Network | Sim Card",
"description": "Core Network Sim Card Configuration",
"software-type": "core-network",
"request": "sim/input-schema.json",
"response": "sim/schema.json",
"shared": true,
"index": 7
},
"ue": {
"title": "UEsim",
"description": "UEsim Configuration",
"software-type": "ue",
"request": "instance-ue-input-schema.json",
"response": "instance-ue-schema.json",
"index": 8
},
"ue/ru": {
"title": "→ UEsim | Radio Unit",
"description": "Configuration of Radio Unit attached to UEsim",
"software-type": "ue",
"shared": true,
"request": "ru/input-schema.json",
"response": "ru/schema.json",
"index": 9
},
"ue/ue": {
"title": "→ UEsim | UE",
"description": "Configuration of UE simulated by UEsim",
"software-type": "ue",
"shared": true,
"request": "ue/input-schema.json",
"response": "ue/schema.json",
"index": 10
},
"ue/cell": {
"title": "→ UEsim | UE Cell",
"description": "Information about Cell to which UEsim attaches",
"software-type": "ue",
"shared": true,
"request": "ue/cell/input-schema.json",
"response": "ue/cell/schema.json",
"index": 11
}
}
}
{
"name": "ORS Amarisoft",
"description": "4G and 5G amarisoft stack for ORS",
"serialisation": "json-in-xml",
"software-type": {
{% if bbu != 'ors' %}
"ue-lte": {
"title": "UE-LTE",
"description": "UE LTE Configuration",
"software-type": "ue-lte",
"request": "instance-{{ software_name }}-ue-lte-input-schema.json",
"response": "instance-{{ software_name }}-ue-lte-schema.json",
"index": 4
},
"ue-nr": {
"title": "UE-NR",
"description": "UE NR Configuration",
"software-type": "ue-nr",
"request": "instance-{{ software_name }}-ue-nr-input-schema.json",
"response": "instance-{{ software_name }}-ue-nr-schema.json",
"index": 5
},
{% endif %}
"enb": {
"title": "eNB",
"software-type": "enb",
"description": "eNodeB Configuration",
"request": "instance-{{ software_name }}-enb-input-schema.json",
"response": "instance-{{ software_name }}-enb-schema.json",
"index": 0
},
"gnb": {
"title": "gNB",
"software-type": "gnb",
"description": "gNodeB Configuration",
"request": "instance-{{ software_name }}-gnb-input-schema.json",
"response": "instance-{{ software_name }}-gnb-schema.json",
"index": 1
},
"core-network": {
"title": "Core Network",
"software-type": "core-network",
"description": "Core Network Configuration",
"request": "instance-core-network-input-schema.json",
"response": "instance-core-network-schema.json",
"index": 2
},
"core-network-slave": {
"title": "Core Network Sim Card",
"description": "Core Network Sim Card Configuration",
"software-type": "core-network",
"request": "instance-core-network-slave-input-schema.json",
"response": "instance-core-network-slave-schema.json",
"shared": true,
"index": 3
}
}
}
# {{ generated_file_message }}
[buildout]
extends =
{%- if bbu == 'ors' %}
software-ors.cfg
{%- else %}
software-base.cfg
{%- endif %}
[default-params]
default-lte-bandwidth = {{ default_lte_bandwidth }}
default-lte-inactivity-timer = {{ default_lte_inactivity_timer }}
default-lte-imsi = {{ default_lte_imsi }}
default-lte-k = {{ default_lte_k }}
default-nr-bandwidth = {{ default_nr_bandwidth }}
default-nr-ssb-pos-bitmap = {{ default_nr_ssb_pos_bitmap }}
default-nr-inactivity-timer = {{ default_nr_inactivity_timer }}
default-nr-imsi = {{ default_nr_imsi }}
default-nr-k = {{ default_nr_k }}
default-n-antenna-dl = {{ default_n_antenna_dl }}
default-n-antenna-ul = {{ default_n_antenna_ul }}
[rf-mode]
software-name = {{ software_name }}
rf-mode = {{ rf_mode }}
trx = {{ trx }}
bbu = {{ bbu }}
ru = {{ ru }}
...@@ -46,6 +46,7 @@ setup( ...@@ -46,6 +46,7 @@ setup(
'slapos.libnetworkcache', 'slapos.libnetworkcache',
'slapos.cookbook', 'slapos.cookbook',
'pcpp', 'pcpp',
'xmltodict',
], ],
zip_safe=True, zip_safe=True,
test_suite='test', test_suite='test',
......
##############################################################################
#
# Copyright (c) 2018 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import json
import glob
import requests
from test import yamlpp_load
from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass
setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software-{{ software_name }}.cfg')))
param_dict = {
'testing': True,
'sim_algo': 'milenage',
'imsi': '001010000000331',
'opc': '000102030405060708090A0B0C0D0E0F',
'amf': '0x9001',
'sqn': '000000000000',
'k': '00112233445566778899AABBCCDDEEFF',
'impu': 'impu331',
'impi': 'impi331@amarisoft.com',
'tx_gain': 17,
'rx_gain': 17,
'dl_earfcn': 325320,
'bandwidth': "10 MHz",
'enb_id': '0x17',
'pci': 250,
'tac': '0x1717',
'root_sequence_index': '1',
'mme_list': {
'10.0.0.1': {'mme_addr': '10.0.0.1'},
'2001:db8::1': {'mme_addr': '2001:db8::1'},
},
'core_network_plmn': '00102',
'dl_nr_arfcn': 325320,
'nr_band': 99,
'nr_bandwidth': 50,
'ssb_nr_arfcn': 377790,
'rue_addr': '192.168.99.88',
'n_antenna_dl': 2,
'n_antenna_ul': 2,
'inactivity_timer': 17,
'gnb_id': '0x17',
'gnb_id_bits': 30,
'ssb_pos_bitmap': '10',
'amf_list': {
'10.0.0.1': {'amf_addr': '10.0.0.1'},
'2001:db8::1': {'amf_addr': '2001:db8::1'},
},
'nr_handover_time_to_trigger': 40,
'nr_handover_a3_offset': 10,
'ncell_list': {
'ORS1': {
'dl_earfcn': 100000,
'dl_nr_arfcn': 100000,
'ssb_nr_arfcn': 100000,
'pci': 1,
'nr_cell_id': '0x0000001',
'cell_id': '0x0000001',
'gnb_id_bits': 28,
'nr_band': 1,
'tac': 1
},
'ORS2': {
'dl_earfcn': 200000,
'dl_nr_arfcn': 200000,
'ssb_nr_arfcn': 200000,
'pci': 2,
'nr_cell_id': '0x0000002',
'cell_id': '0x0000001',
'gnb_id_bits': 30,
'nr_band': 2,
'tac': 2
},
},
'xn_peers': {
'2001:db8::1': {
'xn_addr': '2001:db8::1',
},
'2001:db8::2': {
'xn_addr': '2001:db8::2',
},
},
}
enb_param_dict = {
'plmn_list': {
'00101': {'attach_without_pdn': True, 'plmn': '00101', 'reserved': True},
'00102': {'attach_without_pdn': False, 'plmn': '00102', 'reserved': False},
},
'tdd_ul_dl_config': '[Configuration 6] 5ms 5UL 3DL (maximum uplink)',
}
gnb_param_dict1 = {
'plmn_list': {
'00101': {'plmn': '00101', 'ranac': 1, 'reserved': True, 'tac': 1},
'00102': {'plmn': '00102', 'ranac': 2, 'reserved': False, 'tac': 2},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
gnb_param_dict2 = {
'nssai': {
'0x171717': {'sd': '0x171717', 'sst': 10},
'0x181818': {'sd': '0x181818', 'sst': 20},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
enb_param_dict.update(param_dict)
gnb_param_dict1.update(param_dict)
gnb_param_dict2.update(param_dict)
def test_enb_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], enb_param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], enb_param_dict['rx_gain'])
self.assertEqual(conf['cell_list'][0]['inactivity_timer'], enb_param_dict['inactivity_timer'])
{%- if rf_mode == 'tdd' %}
self.assertEqual(conf['cell_list'][0]['uldl_config'], 6)
{%- else %}
self.assertNotIn('uldl_config', conf['cell_list'][0])
{%- endif %}
self.assertEqual(conf['cell_list'][0]['dl_earfcn'], enb_param_dict['dl_earfcn'])
self.assertEqual(conf['cell_list'][0]['n_rb_dl'], 50)
self.assertEqual(conf['enb_id'], int(enb_param_dict['enb_id'], 16))
self.assertEqual(conf['cell_list'][0]['n_id_cell'], enb_param_dict['pci'])
self.assertEqual(conf['cell_list'][0]['tac'], int(enb_param_dict['tac'], 16))
self.assertEqual(conf['cell_list'][0]['root_sequence_index'], int(enb_param_dict['root_sequence_index']))
self.assertEqual(conf['cell_list'][0]['cell_id'], 0)
for p in conf['cell_default']['plmn_list']:
for n in "plmn attach_without_pdn reserved".split():
self.assertEqual(p[n], enb_param_dict['plmn_list'][p['plmn']][n])
for p in conf['mme_list']:
self.assertEqual(p['mme_addr'], enb_param_dict['mme_list'][p['mme_addr']]['mme_addr'])
for p in conf['cell_list'][0]['ncell_list']:
for k in enb_param_dict['ncell_list']:
if p['dl_earfcn'] == gnb_param_dict1['ncell_list'][k]['dl_earfcn']:
break
conf_ncell = enb_param_dict['ncell_list'][k]
self.assertEqual(p['dl_earfcn'], conf_ncell['dl_earfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['cell_id'], int(conf_ncell['cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
def test_gnb_conf1(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], gnb_param_dict1['tx_gain'])
self.assertEqual(conf['rx_gain'], gnb_param_dict1['rx_gain'])
self.assertEqual(conf['nr_cell_list'][0]['inactivity_timer'], gnb_param_dict1['inactivity_timer'])
self.assertEqual(conf['nr_cell_list'][0]['dl_nr_arfcn'], gnb_param_dict1['dl_nr_arfcn'])
self.assertEqual(conf['nr_cell_list'][0]['band'], gnb_param_dict1['nr_band'])
self.assertEqual(conf['nr_cell_list'][0]['ssb_pos_bitmap'], gnb_param_dict1['ssb_pos_bitmap'])
self.assertEqual(conf['nr_cell_list'][0]['bandwidth'], gnb_param_dict1['nr_bandwidth'])
self.assertEqual(conf['nr_cell_list'][0]['n_id_cell'], gnb_param_dict1['pci'])
self.assertEqual(conf['gnb_id'], int(gnb_param_dict1['gnb_id'], 16))
self.assertEqual(conf['gnb_id_bits'], gnb_param_dict1['gnb_id_bits'])
for p in conf['nr_cell_default']['plmn_list']:
for n in "plmn ranac reserved tac".split():
self.assertEqual(p[n], gnb_param_dict1['plmn_list'][p['plmn']][n])
for p in conf['amf_list']:
self.assertEqual(p['amf_addr'], gnb_param_dict1['amf_list'][p['amf_addr']]['amf_addr'])
for p in conf['xn_peers']:
self.assertEqual(p, gnb_param_dict1['xn_peers'][p]['xn_addr'])
for p in conf['nr_cell_list'][0]['ncell_list']:
for k in gnb_param_dict1['ncell_list']:
if p['dl_nr_arfcn'] == gnb_param_dict1['ncell_list'][k]['dl_nr_arfcn']:
break
conf_ncell = gnb_param_dict1['ncell_list'][k]
self.assertEqual(p['dl_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['ssb_nr_arfcn'], conf_ncell['ssb_nr_arfcn'])
self.assertEqual(p['ul_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['gnb_id_bits'], conf_ncell['gnb_id_bits'])
self.assertEqual(p['nr_cell_id'], int(conf_ncell['nr_cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
self.assertEqual(p['band'], conf_ncell['nr_band'])
tdd_config = conf['nr_cell_list'][0]['tdd_ul_dl_config']['pattern1']
self.assertEqual(float(tdd_config['period']), 2.5)
self.assertEqual(int(tdd_config['dl_slots']), 3)
self.assertEqual(int(tdd_config['dl_symbols']), 10)
self.assertEqual(int(tdd_config['ul_slots']), 1)
self.assertEqual(int(tdd_config['ul_symbols']), 2)
def test_gnb_conf2(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
for p in conf['nr_cell_default']['plmn_list'][0]['nssai']:
sd = hex(p['sd'])
self.assertEqual(sd, gnb_param_dict2['nssai'][sd]['sd'], 16)
self.assertEqual(p['sst'], gnb_param_dict2['nssai'][sd]['sst'])
def test_mme_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'mme.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['plmn'], param_dict['core_network_plmn'])
def test_sim_card(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue_db.cfg'))[0]
conf = yamlpp_load(conf_file)
for n in "sim_algo imsi opc sqn impu impi".split():
self.assertEqual(conf['ue_db'][0][n], param_dict[n])
self.assertEqual(conf['ue_db'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_db'][0]['amf'], int(param_dict['amf'], 16))
p = self.requestSlaveInstance().getConnectionParameterDict()
p = p['_'] if '_' in p else p
self.assertIn('info', p)
def test_monitor_gadget_url(self):
parameters = json.loads(self.computer_partition.getConnectionParameterDict()['_'])
self.assertIn('monitor-gadget-url', parameters)
monitor_setup_url = parameters['monitor-setup-url']
monitor_gadget_url = parameters['monitor-gadget-url']
monitor_base_url = parameters['monitor-base-url']
public_url = monitor_base_url + '/public'
response = requests.get(public_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('software.cfg.html', monitor_gadget_url)
response = requests.get(monitor_gadget_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('<script src="rsvp.js"></script>', response.text)
self.assertIn('<script src="renderjs.js"></script>', response.text)
self.assertIn('<script src="g-chart.line.js"></script>', response.text)
self.assertIn('<script src="promise.gadget.js"></script>', response.text)
class TestENBParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_enb_conf(self):
test_enb_conf(self)
class TestGNBParameters1(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf1(self)
class TestGNBParameters2(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict2)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf2(self)
class TestCoreNetworkParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_mme_conf(self):
test_mme_conf(self)
def requestSlaveInstance(cls):
software_url = cls.getSoftwareURL()
return cls.slap.request(
software_release=software_url,
partition_reference="SIM-CARD",
partition_parameter_kw={'_': json.dumps(param_dict)},
shared=True,
software_type='core-network',
)
class TestENBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestGNBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestCoreNetworkMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True, 'slave-list': []})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUELTEMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUENRMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestSimCard(ORSTestCase):
@classmethod
def requestDefaultInstance(cls, state='started'):
default_instance = super(
ORSTestCase, cls).requestDefaultInstance(state=state)
cls.requestSlaveInstance()
return default_instance
@classmethod
def requestSlaveInstance(cls):
return requestSlaveInstance(cls)
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_sim_card(self):
test_sim_card(self)
class TestUELTEParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_ue_lte_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_earfcn'], param_dict['dl_earfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], 10)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
class TestUENRParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_ue_nr_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['ssb_nr_arfcn'], param_dict['ssb_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_nr_arfcn'], param_dict['dl_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], '10 MHz')
self.assertEqual(conf['cell_groups'][0]['cells'][0]['band'], param_dict['nr_band'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
...@@ -16,10 +16,771 @@ ...@@ -16,10 +16,771 @@
# See COPYING file for full licensing terms. # See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options. # See https://www.nexedi.com/licensing for rationale and options.
# Unit-tests for generic software for Amarisoft 4G/5G stack.
#
# Here we verify only generated configurations because it is not possible to
# run Amarisoft software on testnodes due to licensing restrictions. End-to-end
# testing complements unit-testing by verifying how LTE works for real, but it
# needs dedicated hardware test setup.
#
# Here we test:
#
# - enb (see TestENB_*)
# - uesim (see TestUEsim_*)
#
# Currently there is no tests for core-network, because for core-network
# there is no difference in between generic and ORS modes and core-network is
# already verified by test_ors.
import os
import json
import io import io
import yaml import yaml
import pcpp import pcpp
import xmltodict
import sys
sys.path.insert(0, '../ru')
import xbuildout
import unittest
from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass
setUpModule, _AmariTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software.cfg')))
# ---- building blocks to construct cell/peer parameters ----
#
# - TDD/FDD indicate TDD/FDD mode.
# - LTE/NR indicate LTE/NR cell with given downlink frequency.
# - BW indicates specified bandwidth.
# - CENB indicates a ENB-kind cell.
# - CUE indicates an UE-kind cell.
# - TAC indicates specified Tracking Area Code.
# - LTE_PEER/NR_PEER indicate an LTE/NR ENB-PEER-kind cell.
# - X2_PEER/XN_PEER indicate an LTE/NR ENB peer.
# TDD/FDD are basic parameters to indicate TDD/FDD mode.
TDD = {'rf_mode': 'tdd'}
FDD = {'rf_mode': 'fdd'}
# LTE/NR return basic parameters for an LTE/NR cell with given downlink frequency.
def LTE(dl_earfcn):
return {
'cell_type': 'lte',
'dl_earfcn': dl_earfcn,
}
def NR(dl_nr_arfcn, nr_band):
return {
'cell_type': 'nr',
'dl_nr_arfcn': dl_nr_arfcn,
'nr_band': nr_band,
}
# BW returns basic parameters to indicate specified bandwidth.
def BW(bandwidth):
return {
'bandwidth': bandwidth,
}
# CENB returns basic parameters to indicate a ENB-kind cell.
def CENB(cell_id, pci):
return {
'cell_kind': 'enb',
'cell_id': '0x%02x' % cell_id,
'pci': pci,
}
# CUE indicates an UE-kind cell.
CUE = {'cell_kind': 'ue'}
# TAC returns basic parameters to indicate specified Tracking Area Code.
def TAC(tac):
return {
'tac': '0x%x' % tac,
}
# LTE_PEER/NR_PEER return basic parameters to indicate an LTE/NR ENB-PEER-kind cell.
def LTE_PEER(e_cell_id, pci, tac):
return {
'cell_kind': 'enb_peer',
'e_cell_id': '0x%07x' % e_cell_id,
'pci': pci,
'tac': '0x%x' % tac,
}
def NR_PEER(nr_cell_id, gnb_id_bits, pci, tac):
return {
'cell_kind': 'enb_peer',
'nr_cell_id': '0x%09x' % nr_cell_id,
'gnb_id_bits': gnb_id_bits,
'pci': pci,
'tac': tac,
}
# X2_PEER/XN_PEER return basic parameters to indicate an LTE/NR ENB peer.
def X2_PEER(x2_addr):
return {
'peer_type': 'lte',
'x2_addr': x2_addr,
}
def XN_PEER(xn_addr):
return {
'peer_type': 'nr',
'xn_addr': xn_addr,
}
# --------
# AmariTestCase is base class for all tests.
class AmariTestCase(_AmariTestCase):
maxDiff = None # show full diff in test run log on an error
# stress correctness of ru_ref/cell_ref/... usage throughout all places in
# buildout code - special characters should not lead to wrong templates or
# code injection.
default_partition_reference = _AmariTestCase.default_partition_reference + \
' ${a:b}\n[c]\n;'
# faster edit/try cycle when enabled (handy during development)
if 0:
instance_max_retry = 1
report_max_retry = 1
@classmethod
def requestDefaultInstance(cls, state='started'):
inst = super().requestDefaultInstance(state=state)
cls.requestAllShared(inst)
return inst
# requestAllShared should add all shared instances of the testcase over imain.
@classmethod
def requestAllShared(cls, imain):
raise NotImplementedError
# requestShared requests one shared instance over imain with specified subreference and parameters.
@classmethod
def requestShared(cls, imain, subref, ctx):
ref = cls.ref(subref)
kw = dict(
software_release=cls.getSoftwareURL(),
software_type=cls.getInstanceSoftwareType(),
partition_reference=ref,
# XXX StandaloneSlapOS rejects filter_kw with "Can only request on embedded computer"
#filter_kw = {'instance_guid': imain.getInstanceGuid()},
partition_parameter_kw={'_': json.dumps(ctx)},
shared=True)
cls._requested[ref] = kw
return cls.slap.request(**kw)
# XXX StandaloneSlapOS lacks getInformation - we remember the way instances are requested ourselves.
_requested = {} # ref -> kw used for slap.request
# queryPublished and querySharedPublished return information published by
# an instance / shared instance correspondingly.
@classmethod
def querySharedPublished(cls, subref):
return cls.queryPublished(cls.ref(subref))
@classmethod
def queryPublished(cls, ref):
# see ^^^ about lack of getInformation on StandaloneSlapOS
#inst = cls.slap.getInformation(computer_partition=ref)
inst = cls.slap.request(**cls._requested[ref])
iconn = inst.getConnectionParameterDict()
return json.loads(iconn['_'])
# ref returns full reference of shared instance with given subreference.
#
# for example if reference of main instance is 'MAIN-INSTANCE'
#
# ref('RU') = 'MAIN-INSTANCE.RU'
@classmethod
def ref(cls, subref):
return '%s.%s' % (cls.default_partition_reference, subref)
# ipath returns path for a file inside main instance.
@classmethod
def ipath(cls, path):
assert path[:1] != '/', path
return '%s/%s' % (cls.computer_partition_root_path, path)
# ---- eNB + base class for similar services that do radio ----
# RFTestCase4 is base class for tests of all services that do radio.
#
# It instantiates a service with several Radio Units and Cells attached:
#
# 4 RU x 4 CELL are requested to verify all {FDD,TDD}·{LTE,NR} combinations.
#
# In requested instances mostly non-overlapping range of numbers are
# assigned to parameters according to the following scheme:
#
# 0+ cell_id
# 0x10+ pci
# 0x100+ tac
# 10+ tx_gain
# 20+ rx_gain
# xxx+i·100 dl_arfcn
# 5,10,15,20 bandwidth
# 100+ root_sequence_index
# 1000+ inactivity_timer
#
# this allows to quickly see offhand to which cell/ru and parameter a
# particular number belongs to.
#
# Subclasses should define:
#
# - RUcfg(i) to return primary parameters specific for i'th RU configuration
# like ru_type - to verify particular RU driver, sdr_dev, sfp_port and so on.
# - CELLcfg(i) to tune parameters of i'th cell, for example cell_kind.
# - .rf_cfg with loaded service config.
class RFTestCase4(AmariTestCase):
@classmethod
def requestAllShared(cls, imain):
def RU(i):
ru = cls.RUcfg(i)
ru |= {'n_antenna_dl': 4, 'n_antenna_ul': 2}
ru |= {'tx_gain': 10+i, 'rx_gain': 20+i, 'txrx_active': 'ACTIVE'}
return cls.requestShared(imain, 'RU%d' % i, ru)
def CELL(i, ctx):
cell = {
'ru': {
'ru_type': 'ru_ref',
'ru_ref': cls.ref('RU%d' % i),
}
}
cell |= cls.CELLcfg(i)
cell |= ctx
return cls.requestShared(imain, 'RU%d.CELL' % i, cell)
RU(1); CELL(1, FDD | LTE( 100) | BW( 5))
RU(2); CELL(2, TDD | LTE( 40200) | BW(10))
RU(3); CELL(3, FDD | NR (300300,74) | BW(15))
RU(4); CELL(4, TDD | NR (470400,40) | BW(20))
def test_rf_cfg_txrx_gain(t):
# NOTE even though setting tx_gain/rx_gain in enb.cfg does not make any
# difference for CPRI case, we still do set it there for consistency.
# For the reference: for CPRI case the real tx/rx gain is set in
# RU configuration and is verified by RU tests.
t.assertEqual(t.rf_cfg['tx_gain'], [11]*4 + [12]*4 + [13]*4 + [14]*4)
t.assertEqual(t.rf_cfg['rx_gain'], [21]*2 + [22]*2 + [23]*2 + [24]*2)
def test_published_ru_and_cell(t):
q = t.querySharedPublished
assertMatch(t, q('RU1'), {'tx_gain': 11, 'rx_gain': 21, 'txrx_active': 'ACTIVE'})
assertMatch(t, q('RU2'), {'tx_gain': 12, 'rx_gain': 22, 'txrx_active': 'ACTIVE'})
assertMatch(t, q('RU3'), {'tx_gain': 13, 'rx_gain': 23, 'txrx_active': 'ACTIVE'})
assertMatch(t, q('RU4'), {'tx_gain': 14, 'rx_gain': 24, 'txrx_active': 'ACTIVE'})
assertMatch(t, q('RU1.CELL'), dict(band='b1',
dl_earfcn= 100, ul_earfcn=18100,
dl_nr_arfcn=NO, ul_nr_arfcn=NO, ssb_nr_arfcn=NO))
assertMatch(t, q('RU2.CELL'), dict(band='b41',
dl_earfcn=40200, ul_earfcn=40200,
dl_nr_arfcn=NO, ul_nr_arfcn=NO, ssb_nr_arfcn=NO))
assertMatch(t, q('RU3.CELL'), dict(band='n74',
dl_earfcn=NO, ul_earfcn=NO,
dl_nr_arfcn=300300, ul_nr_arfcn=290700, ssb_nr_arfcn=300270))
assertMatch(t, q('RU4.CELL'), dict(band='n40',
dl_earfcn=NO, ul_earfcn=NO,
dl_nr_arfcn=470400, ul_nr_arfcn=470400, ssb_nr_arfcn=470430))
# ENBTestCase4 provides base class for unit-testing eNB service.
#
# It instantiates enb with 4 Radio Units x 4 Cells and verifies generated
# enb.cfg to match what is expected.
class ENBTestCase4(RFTestCase4):
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.enb_cfg = cls.rf_cfg = yamlpp_load(cls.ipath('etc/enb.cfg'))
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({
'testing': True,
'enb_id': '0x17',
'gnb_id': '0x23',
'gnb_id_bits': 30,
'mme_list': {
'1': {'mme_addr': '1.2.3.4'},
'2': {'mme_addr': '[abcd:5::1]:78'},
},
'amf_list': {
'1': {'amf_addr': '4.3.2.1:77'},
'2': {'amf_addr': 'dcba:5::1'},
},
'plmn_list': {
'1': {'plmn': '31415'},
'2': {'plmn': '44444', 'attach_without_pdn': True, 'reserved': True},
},
'plmn_list_5g': {
'1': {'plmn': '51413', 'tac': 0x124},
'2': {'plmn': '55555', 'tac': 0x125, 'ranac': 210, 'reserved': True},
},
})}
@classmethod
def requestAllShared(cls, imain):
super().requestAllShared(imain)
def _(subref, ctx):
return cls.requestShared(imain, subref, ctx)
_('PEER4', X2_PEER('44.1.1.1'))
_('PEER5', XN_PEER('55.1.1.1'))
_('PEERCELL4', LTE(700) | LTE_PEER(0x12345, 35, 0x123))
_('PEERCELL5', NR(520000,38) | NR_PEER(0x77712,22, 75, 0x321))
cls.ho_inter = [
dict(rat='eutra', cell_id=0x12345, n_id_cell=35, dl_earfcn= 700, tac=0x123),
dict(rat='nr', nr_cell_id=0x77712, gnb_id_bits=22, n_id_cell=75,
dl_nr_arfcn=520000, ul_nr_arfcn=520000, ssb_nr_arfcn=520090, band=38,
tac = 0x321),
]
def CELLcfg(i):
return CENB(i, 0x10+i) | TAC(0x100+i) | {
'root_sequence_index': 100+i,
'inactivity_timer': 1000+i}
# basic enb parameters
def test_enb_cfg_basic(t):
assertMatch(t, t.enb_cfg, dict(
enb_id=0x17, gnb_id=0x23, gnb_id_bits=30,
mme_list=[{'mme_addr': '1.2.3.4'}, {'mme_addr': '[abcd:5::1]:78'}],
amf_list=[{'amf_addr': '4.3.2.1:77'}, {'amf_addr': 'dcba:5::1'}],
x2_peers=['44.1.1.1'], xn_peers=['55.1.1.1'],
cell_default={
'plmn_list': [
dict(plmn='31415', attach_without_pdn=False, reserved=False),
dict(plmn='44444', attach_without_pdn=True, reserved=True),
]
},
nr_cell_default={
'plmn_list': [
dict(plmn='51413', tac=0x124, ranac=NO, reserved=False),
dict(plmn='55555', tac=0x125, ranac=210, reserved=True),
]
},
))
# basic cell parameters
def test_enb_cfg_cell(t):
assertMatch(t, t.enb_cfg['cell_list'], [
dict( # CELL1
uldl_config=NO, rf_port=0, n_antenna_dl=4, n_antenna_ul=2,
dl_earfcn=100, ul_earfcn=18100,
n_rb_dl=25,
cell_id=0x1, n_id_cell=0x11, tac=0x101,
root_sequence_index=101, inactivity_timer=1001,
),
dict( # CELL2
uldl_config=2, rf_port=1, n_antenna_dl=4, n_antenna_ul=2,
dl_earfcn=40200, ul_earfcn=40200,
n_rb_dl=50,
cell_id=0x2, n_id_cell=0x12, tac=0x102,
root_sequence_index=102, inactivity_timer=1002,
),
])
assertMatch(t, t.enb_cfg['nr_cell_list'], [
dict( # CELL3
tdd_ul_dl_config=NO, rf_port=2, n_antenna_dl=4, n_antenna_ul=2,
dl_nr_arfcn=300300, ul_nr_arfcn=290700, ssb_nr_arfcn=300270, band=74,
bandwidth=15,
cell_id=0x3, n_id_cell=0x13, tac=NO,
root_sequence_index=103, inactivity_timer=1003,
),
dict( # CELL4
tdd_ul_dl_config={'pattern1': dict(
period=5, dl_slots=7, dl_symbols=6, ul_slots=2, ul_symbols=4,
)},
rf_port=3, n_antenna_dl=4, n_antenna_ul=2,
dl_nr_arfcn=470400, ul_nr_arfcn=470400, ssb_nr_arfcn=470430, band=40,
bandwidth=20,
cell_id=0x4, n_id_cell=0x14, tac=NO,
root_sequence_index=104, inactivity_timer=1004,
),
])
# Carrier Aggregation
def test_enb_cfg_ca(t):
assertMatch(t, t.enb_cfg['cell_list'], [
{ # CELL1
'scell_list': [{'cell_id': 2}], # LTE + LTE
'en_dc_scg_cell_list': [{'cell_id': 3}, {'cell_id': 4}], # LTE + NR
},
{ # CELL2
'scell_list': [{'cell_id': 1}], # LTE + LTE
'en_dc_scg_cell_list': [{'cell_id': 3}, {'cell_id': 4}], # LTE + NR
},
])
assertMatch(t, t.enb_cfg['nr_cell_list'], [
{ # CELL3
'scell_list': [{'cell_id': 4}], # NR + NR
},
{ # CELL4
'scell_list': [{'cell_id': 3}], # NR + NR
},
])
# Handover
def test_enb_cfg_ho(t):
assertMatch(t, t.enb_cfg['cell_list'], [
{ # CELL1
'ncell_list': [
dict(rat='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=40200, tac=0x102), # CELL2
dict(rat='nr', cell_id= 3), # CELL3
dict(rat='nr', cell_id= 4), # CELL4
] + t.ho_inter,
},
{ # CELL2
'ncell_list': [
dict(rat='eutra', cell_id= 0x1701, n_id_cell=0x11, dl_earfcn= 100, tac=0x101), # CELL1
dict(rat='nr', cell_id= 3), # CELL3
dict(rat='nr', cell_id= 4), # CELL4
] + t.ho_inter,
},
])
assertMatch(t, t.enb_cfg['nr_cell_list'], [
{ # CELL3
'ncell_list': [
dict(rat='eutra', cell_id= 0x1701, n_id_cell=0x11, dl_earfcn= 100, tac=0x101), # CELL1
dict(rat='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=40200, tac=0x102), # CELL2
dict(rat='nr', cell_id= 4), # CELL4
] + t.ho_inter,
},
{ # CELL4
'ncell_list': [
dict(rat='eutra', cell_id= 0x1701, n_id_cell=0x11, dl_earfcn= 100, tac=0x101), # CELL1
dict(rat='eutra', cell_id= 0x1702, n_id_cell=0x12, dl_earfcn=40200, tac=0x102), # CELL2
dict(rat='nr', cell_id= 3), # CELL3
] + t.ho_inter,
},
])
# ---- RU mixins to be used with RFTestCase4 ----
# SDR4 is mixin to verify SDR driver wrt all LTE/NR x FDD/TDD modes.
class SDR4:
@classmethod
def RUcfg(cls, i):
return {
'ru_type': 'sdr',
'ru_link_type': 'sdr',
'sdr_dev_list': [2*i,2*i+1],
}
# radio units configuration
def test_rf_cfg_ru(t):
assertMatch(t, t.rf_cfg['rf_driver'], dict(
name='sdr',
args='dev0=/dev/sdr2,dev1=/dev/sdr3,dev2=/dev/sdr4,dev3=/dev/sdr5,' +
'dev4=/dev/sdr6,dev5=/dev/sdr7,dev6=/dev/sdr8,dev7=/dev/sdr9',
cpri_mapping=NO,
cpri_mult=NO,
cpri_rx_delay=NO,
cpri_tx_delay=NO,
cpri_tx_dbm=NO,
))
# Lopcomm4 is mixin to verify Lopcomm driver wrt all LTE/NR x FDD/TDD modes.
class Lopcomm4:
@classmethod
def RUcfg(cls, i):
return {
'ru_type': 'lopcomm',
'ru_link_type': 'cpri',
'cpri_link': {
'sdr_dev': 0,
'sfp_port': i,
'mult': 4,
'mapping': 'hw',
'rx_delay': 40+i,
'tx_delay': 50+i,
'tx_dbm': 60+i
},
'mac_addr': '00:0A:45:00:00:%02x' % i,
}
# radio units configuration in enb.cfg
def test_rf_cfg_ru(t):
assertMatch(t, t.rf_cfg['rf_driver'], dict(
name='sdr',
args='dev0=/dev/sdr0@1,dev1=/dev/sdr0@2,dev2=/dev/sdr0@3,dev3=/dev/sdr0@4',
cpri_mapping='hw,hw,hw,hw',
cpri_mult='4,4,4,4',
cpri_rx_delay='41,42,43,44',
cpri_tx_delay='51,52,53,54',
cpri_tx_dbm='61,62,63,64',
))
# RU configuration in cu_config.xml
def test_ru_cu_config_xml(t):
def uctx(rf_mode, cell_type, dl_arfcn, ul_arfcn, bw, dl_freq, ul_freq, tx_gain, rx_gain):
return {
'tx-array-carriers': {
'rw-duplex-scheme': rf_mode,
'rw-type': cell_type,
'absolute-frequency-center': '%d' % dl_arfcn,
'center-of-channel-bandwidth': '%d' % dl_freq,
'channel-bandwidth': '%d' % bw,
'gain': '%d' % tx_gain,
'active': 'ACTIVE',
},
'rx-array-carriers': {
'absolute-frequency-center': '%d' % ul_arfcn,
'center-of-channel-bandwidth': '%d' % ul_freq,
'channel-bandwidth': '%d' % bw,
# XXX no rx_gain
'active': 'ACTIVE',
},
}
_ = t._test_ru_cu_config_xml
# rf_mode ctype dl_arfcn ul_arfcn bw dl_freq ul_freq txg rxg
_(1, uctx('FDD', 'LTE', 100, 18100, 5000000, 2120000000, 1930000000, 11, 21))
_(2, uctx('TDD', 'LTE', 40200, 40200, 10000000, 2551000000, 2551000000, 12, 22))
_(3, uctx('FDD', 'NR', 300300, 290700, 15000000, 1501500000, 1453500000, 13, 23))
_(4, uctx('TDD', 'NR', 470400, 470400, 20000000, 2352000000, 2352000000, 14, 24))
def _test_ru_cu_config_xml(t, i, uctx):
cu_xml = t.ipath('etc/%s' % xbuildout.encode('%s-cu_config.xml' % t.ref('RU%d' % i)))
with open(cu_xml, 'r') as f:
cu = f.read()
cu = xmltodict.parse(cu)
assertMatch(t, cu, {
'xc:config': {
'user-plane-configuration': {
'tx-endpoints': [
{'name': 'TXA0P00C00', 'e-axcid': {'eaxc-id': '0'}},
{'name': 'TXA0P00C01', 'e-axcid': {'eaxc-id': '1'}},
{'name': 'TXA0P01C00', 'e-axcid': {'eaxc-id': '2'}},
{'name': 'TXA0P01C01', 'e-axcid': {'eaxc-id': '3'}},
],
'tx-links': [
{'name': 'TXA0P00C00', 'tx-endpoint': 'TXA0P00C00'},
{'name': 'TXA0P00C01', 'tx-endpoint': 'TXA0P00C01'},
{'name': 'TXA0P01C00', 'tx-endpoint': 'TXA0P01C00'},
{'name': 'TXA0P01C01', 'tx-endpoint': 'TXA0P01C01'},
],
'rx-endpoints': [
{'name': 'RXA0P00C00', 'e-axcid': {'eaxc-id': '0'}},
{'name': 'PRACH0P00C00', 'e-axcid': {'eaxc-id': '8'}},
{'name': 'RXA0P00C01', 'e-axcid': {'eaxc-id': '1'}},
{'name': 'PRACH0P00C01', 'e-axcid': {'eaxc-id': '24'}},
],
'rx-links': [
{'name': 'RXA0P00C00', 'rx-endpoint': 'RXA0P00C00'},
{'name': 'PRACH0P00C00', 'rx-endpoint': 'PRACH0P00C00'},
{'name': 'RXA0P00C01', 'rx-endpoint': 'RXA0P00C01'},
{'name': 'PRACH0P00C01', 'rx-endpoint': 'PRACH0P00C01'},
],
} | uctx
}
})
# Sunwave4 is mixin to verify Sunwave driver wrt all LTE/NR x FDD/TDD modes.
class Sunwave4:
@classmethod
def RUcfg(cls, i):
return {
'ru_type': 'sunwave',
'ru_link_type': 'cpri',
'cpri_link': {
'sdr_dev': 1,
'sfp_port': i,
'mult': 5,
'mapping': 'bf1',
'rx_delay': 140+i,
'tx_delay': 150+i,
'tx_dbm': 160+i
},
'mac_addr': '00:FA:FE:00:00:%02x' % i,
}
# radio units configuration in enb.cfg
def test_rf_cfg_ru(t):
assertMatch(t, t.rf_cfg['rf_driver'], dict(
name='sdr',
args='dev0=/dev/sdr1@1,dev1=/dev/sdr1@2,dev2=/dev/sdr1@3,dev3=/dev/sdr1@4',
cpri_mapping='bf1,bf1,bf1,bf1',
cpri_mult='5,5,5,5',
cpri_rx_delay='141,142,143,144',
cpri_tx_delay='151,152,153,154',
cpri_tx_dbm='161,162,163,164',
))
# RUMultiType4 is mixin to verify that different RU types can be used at the same time.
class RUMultiType4:
# ENB does not support mixing SDR + CPRI - verify only with CPRI-based units
# see https://support.amarisoft.com/issues/26021 for details
@classmethod
def RUcfg(cls, i):
assert 1 <= i <= 4, i
if i in (1,2):
return Lopcomm4.RUcfg(i)
else:
return Sunwave4.RUcfg(i)
# radio units configuration in enb.cfg
def test_rf_cfg_ru(t):
assertMatch(t, t.rf_cfg['rf_driver'], dict(
name='sdr',
args='dev0=/dev/sdr0@1,dev1=/dev/sdr0@2,dev2=/dev/sdr1@3,dev3=/dev/sdr1@4',
cpri_mapping='hw,hw,bf1,bf1',
cpri_mult='4,4,5,5',
cpri_rx_delay='41,42,143,144',
cpri_tx_delay='51,52,153,154',
cpri_tx_dbm='61,62,163,164',
))
# instantiate eNB tests
class TestENB_SDR4 (ENBTestCase4, SDR4): pass
class TestENB_Lopcomm4 (ENBTestCase4, Lopcomm4): pass
class TestENB_Sunwave4 (ENBTestCase4, Sunwave4): pass
class TestENB_RUMultiType4(ENBTestCase4, RUMultiType4): pass
# ---- UEsim ----
# UEsimTestCase4 provides base class for unit-testing UEsim service.
#
# It is similar to ENBTestCase4 but configures UE cells instead of eNB cells.
class UEsimTestCase4(RFTestCase4):
@classmethod
def getInstanceSoftwareType(cls):
return "ue"
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.ue_cfg = cls.rf_cfg = yamlpp_load(cls.ipath('etc/ue.cfg'))
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({
'testing': True,
})}
@classmethod
def CELLcfg(cls, i):
return CUE
@classmethod
def requestAllShared(cls, imain):
super().requestAllShared(imain)
def UE(i):
ue = {
'ue_type': ('lte', 'nr') [(i-1) % 2],
'rue_addr': 'host%d' % i,
'sim_algo': ('xor', 'milenage', 'tuak') [i-1],
'imsi': '%015d' % i,
'opc': '%032x' % i,
'amf': '0x%04x' % (0x9000+i),
'sqn': '%012x' % i,
'k': 'FFFF%028x' % i,
'impi': 'impi%d@rapid.space' % i,
}
return cls.requestShared(imain, 'UE%d' % i, ue)
UE(1)
UE(2)
UE(3)
# ue parameters
def test_ue_cfg_ue(t):
assertMatch(t, t.ue_cfg['ue_list'], [
dict(
as_release=13, ue_category=13, rue_addr='host1',
sim_algo='xor', amf =0x9001, impi='impi1@rapid.space',
sqn ='000000000001',
imsi='000000000000001',
opc ='00000000000000000000000000000001',
K ='FFFF0000000000000000000000000001',
),
dict(
as_release=15, ue_category='nr', rue_addr='host2',
sim_algo='milenage', amf =0x9002, impi='impi2@rapid.space',
sqn ='000000000002',
imsi='000000000000002',
opc ='00000000000000000000000000000002',
K ='FFFF0000000000000000000000000002',
),
dict(
as_release=13, ue_category=13, rue_addr='host3',
sim_algo='tuak', amf =0x9003, impi='impi3@rapid.space',
sqn ='000000000003',
imsi='000000000000003',
opc ='00000000000000000000000000000003',
K ='FFFF0000000000000000000000000003',
),
])
# cells
def test_ue_cfg_cell(t):
assertMatch(t, t.ue_cfg['cell_groups'], [
dict(
group_type='lte',
cells=[
dict( # CELL1
rf_port=0, n_antenna_dl=4, n_antenna_ul=2,
dl_earfcn=100, ul_earfcn=18100,
bandwidth=5,
),
dict( # CELL2
rf_port=1, n_antenna_dl=4, n_antenna_ul=2,
dl_earfcn=40200, ul_earfcn=40200,
bandwidth=10,
),
]
),
dict(
group_type='nr',
cells=[
dict( # CELL3
rf_port=2, n_antenna_dl=4, n_antenna_ul=2,
dl_nr_arfcn=300300, ul_nr_arfcn=290700, ssb_nr_arfcn=300270, band=74,
bandwidth=15,
),
dict( # CELL4
rf_port=3, n_antenna_dl=4, n_antenna_ul=2,
dl_nr_arfcn=470400, ul_nr_arfcn=470400, ssb_nr_arfcn=470430, band=40,
bandwidth=20,
),
]
)
])
# instantiate UEsim tests
class TestUEsim_SDR4 (UEsimTestCase4, SDR4): pass
class TestUEsim_Lopcomm4 (UEsimTestCase4, Lopcomm4): pass
class TestUEsim_Sunwave4 (UEsimTestCase4, Sunwave4): pass
class TestUEsim_RUMultiType4(UEsimTestCase4, RUMultiType4): pass
# ---- misc ---- # ---- misc ----
...@@ -36,3 +797,96 @@ def yamlpp_load(path): ...@@ -36,3 +797,96 @@ def yamlpp_load(path):
p.write(f) p.write(f)
data_ = f.getvalue() # preprocessed input data_ = f.getvalue() # preprocessed input
return yaml.load(data_, Loader=yaml.Loader) return yaml.load(data_, Loader=yaml.Loader)
# assertMatch recursively matches data structure against specified pattern.
#
# - dict match by verifying v[k] == vok[k] for keys from the pattern.
# vok[k]=NO means v[k] must be absent
# - list match by matching all elements individually
# - atomic types like int and str match by equality
class NOClass:
def __repr__(self):
return 'ø'
NO = NOClass()
def assertMatch(t: unittest.TestCase, v, vok):
v_ = _matchCollect(v, vok)
t.assertEqual(v_, vok)
def _matchCollect(v, vok):
if type(v) is not type(vok):
return v
if type(v) is dict:
v_ = {}
for k in vok:
v_[k] = _matchCollect(v.get(k, NO), vok[k])
return v_
if type(v) is list:
v_ = []
for i in range(max(len(v), len(vok))):
e = NO
eok = NO
if i < len(v):
e = v[i]
if i < len(vok):
eok = vok[i]
if e is not NO:
if eok is not NO:
v_.append(_matchCollect(e, eok))
else:
v_.append(e)
return v_
# other types, e.g. atomic int/str/... - return as is
assert type(v) is not tuple, v
return v
class TestAssertMatch(unittest.TestCase):
def test_assertMatch(t):
y, n = True, False
testv = [ # [](match, v, vok)
(y, 12, 12),
(n, 12, 13),
(n, 12, '12'),
(y, 'a', 'a'),
(n, 'a', 'ab'),
(y, [], []),
(n, [], [1]),
(y, [1], [1]),
(n, [1,2], [1]),
(y, [1,2], [1,2]),
(n, [1,2], ['a',2]),
(y, {}, {}),
(y, {'a': 1}, {}),
(y, {'a': 1}, {'a': 1}),
(n, {'a': 1}, {'a': 2}),
(n, {'a': 1}, {'a': NO}),
(y, {}, {'a': NO}),
(y, {'b': 2}, {'a': NO}),
(n, {'a': 1, 'b': 2}, {'a': NO}),
(n, {'a': 1, 'b': 2}, {'a': NO, 'b': 2}),
(y, {'a': 1, 'b': 2}, { 'b': 2}),
(y, {'a': [1, 2, {'aa': 33, 'bb': 44}]},
{'a': [1, 2, {'aa': 33, 'cc': NO}]}),
(n, {'a': [1, 2, {'aa': 33, 'bb': 44}]},
{'a': [1, 2, {'aa': 35, 'cc': NO}]}),
]
for mok, v, vok in testv:
with t.subTest(mok=mok, v=v, vok=vok):
if mok:
assertMatch(t, v, vok)
else:
t.assertRaises(t.failureException,
assertMatch, t, v, vok)
# hide base TestCases from unittest discovery so that their test_ methods are
# run only on leaf test classes.
def __dir__():
d = list(sorted(globals().keys()))
abstract = {'AmariTestCase', 'RFTestCase4', 'ENBTestCase4', 'UEsimTestCase4'}
for _ in abstract:
d.remove(_)
return d
##############################################################################
#
# Copyright (c) 2018 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import json
import glob
import requests
from test import yamlpp_load
from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass
setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software-fdd-lopcomm.cfg')))
param_dict = {
'testing': True,
'sim_algo': 'milenage',
'imsi': '001010000000331',
'opc': '000102030405060708090A0B0C0D0E0F',
'amf': '0x9001',
'sqn': '000000000000',
'k': '00112233445566778899AABBCCDDEEFF',
'impu': 'impu331',
'impi': 'impi331@amarisoft.com',
'tx_gain': 17,
'rx_gain': 17,
'dl_earfcn': 325320,
'bandwidth': "10 MHz",
'enb_id': '0x17',
'pci': 250,
'tac': '0x1717',
'root_sequence_index': '1',
'mme_list': {
'10.0.0.1': {'mme_addr': '10.0.0.1'},
'2001:db8::1': {'mme_addr': '2001:db8::1'},
},
'core_network_plmn': '00102',
'dl_nr_arfcn': 325320,
'nr_band': 99,
'nr_bandwidth': 50,
'ssb_nr_arfcn': 377790,
'rue_addr': '192.168.99.88',
'n_antenna_dl': 2,
'n_antenna_ul': 2,
'inactivity_timer': 17,
'gnb_id': '0x17',
'gnb_id_bits': 30,
'ssb_pos_bitmap': '10',
'amf_list': {
'10.0.0.1': {'amf_addr': '10.0.0.1'},
'2001:db8::1': {'amf_addr': '2001:db8::1'},
},
'nr_handover_time_to_trigger': 40,
'nr_handover_a3_offset': 10,
'ncell_list': {
'ORS1': {
'dl_earfcn': 100000,
'dl_nr_arfcn': 100000,
'ssb_nr_arfcn': 100000,
'pci': 1,
'nr_cell_id': '0x0000001',
'cell_id': '0x0000001',
'gnb_id_bits': 28,
'nr_band': 1,
'tac': 1
},
'ORS2': {
'dl_earfcn': 200000,
'dl_nr_arfcn': 200000,
'ssb_nr_arfcn': 200000,
'pci': 2,
'nr_cell_id': '0x0000002',
'cell_id': '0x0000001',
'gnb_id_bits': 30,
'nr_band': 2,
'tac': 2
},
},
'xn_peers': {
'2001:db8::1': {
'xn_addr': '2001:db8::1',
},
'2001:db8::2': {
'xn_addr': '2001:db8::2',
},
},
}
enb_param_dict = {
'plmn_list': {
'00101': {'attach_without_pdn': True, 'plmn': '00101', 'reserved': True},
'00102': {'attach_without_pdn': False, 'plmn': '00102', 'reserved': False},
},
'tdd_ul_dl_config': '[Configuration 6] 5ms 5UL 3DL (maximum uplink)',
}
gnb_param_dict1 = {
'plmn_list': {
'00101': {'plmn': '00101', 'ranac': 1, 'reserved': True, 'tac': 1},
'00102': {'plmn': '00102', 'ranac': 2, 'reserved': False, 'tac': 2},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
gnb_param_dict2 = {
'nssai': {
'0x171717': {'sd': '0x171717', 'sst': 10},
'0x181818': {'sd': '0x181818', 'sst': 20},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
enb_param_dict.update(param_dict)
gnb_param_dict1.update(param_dict)
gnb_param_dict2.update(param_dict)
def test_enb_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], enb_param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], enb_param_dict['rx_gain'])
self.assertEqual(conf['cell_list'][0]['inactivity_timer'], enb_param_dict['inactivity_timer'])
self.assertNotIn('uldl_config', conf['cell_list'][0])
self.assertEqual(conf['cell_list'][0]['dl_earfcn'], enb_param_dict['dl_earfcn'])
self.assertEqual(conf['cell_list'][0]['n_rb_dl'], 50)
self.assertEqual(conf['enb_id'], int(enb_param_dict['enb_id'], 16))
self.assertEqual(conf['cell_list'][0]['n_id_cell'], enb_param_dict['pci'])
self.assertEqual(conf['cell_list'][0]['tac'], int(enb_param_dict['tac'], 16))
self.assertEqual(conf['cell_list'][0]['root_sequence_index'], int(enb_param_dict['root_sequence_index']))
self.assertEqual(conf['cell_list'][0]['cell_id'], 0)
for p in conf['cell_default']['plmn_list']:
for n in "plmn attach_without_pdn reserved".split():
self.assertEqual(p[n], enb_param_dict['plmn_list'][p['plmn']][n])
for p in conf['mme_list']:
self.assertEqual(p['mme_addr'], enb_param_dict['mme_list'][p['mme_addr']]['mme_addr'])
for p in conf['cell_list'][0]['ncell_list']:
for k in enb_param_dict['ncell_list']:
if p['dl_earfcn'] == gnb_param_dict1['ncell_list'][k]['dl_earfcn']:
break
conf_ncell = enb_param_dict['ncell_list'][k]
self.assertEqual(p['dl_earfcn'], conf_ncell['dl_earfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['cell_id'], int(conf_ncell['cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
def test_gnb_conf1(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], gnb_param_dict1['tx_gain'])
self.assertEqual(conf['rx_gain'], gnb_param_dict1['rx_gain'])
self.assertEqual(conf['nr_cell_list'][0]['inactivity_timer'], gnb_param_dict1['inactivity_timer'])
self.assertEqual(conf['nr_cell_list'][0]['dl_nr_arfcn'], gnb_param_dict1['dl_nr_arfcn'])
self.assertEqual(conf['nr_cell_list'][0]['band'], gnb_param_dict1['nr_band'])
self.assertEqual(conf['nr_cell_list'][0]['ssb_pos_bitmap'], gnb_param_dict1['ssb_pos_bitmap'])
self.assertEqual(conf['nr_cell_list'][0]['bandwidth'], gnb_param_dict1['nr_bandwidth'])
self.assertEqual(conf['nr_cell_list'][0]['n_id_cell'], gnb_param_dict1['pci'])
self.assertEqual(conf['gnb_id'], int(gnb_param_dict1['gnb_id'], 16))
self.assertEqual(conf['gnb_id_bits'], gnb_param_dict1['gnb_id_bits'])
for p in conf['nr_cell_default']['plmn_list']:
for n in "plmn ranac reserved tac".split():
self.assertEqual(p[n], gnb_param_dict1['plmn_list'][p['plmn']][n])
for p in conf['amf_list']:
self.assertEqual(p['amf_addr'], gnb_param_dict1['amf_list'][p['amf_addr']]['amf_addr'])
for p in conf['xn_peers']:
self.assertEqual(p, gnb_param_dict1['xn_peers'][p]['xn_addr'])
for p in conf['nr_cell_list'][0]['ncell_list']:
for k in gnb_param_dict1['ncell_list']:
if p['dl_nr_arfcn'] == gnb_param_dict1['ncell_list'][k]['dl_nr_arfcn']:
break
conf_ncell = gnb_param_dict1['ncell_list'][k]
self.assertEqual(p['dl_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['ssb_nr_arfcn'], conf_ncell['ssb_nr_arfcn'])
self.assertEqual(p['ul_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['gnb_id_bits'], conf_ncell['gnb_id_bits'])
self.assertEqual(p['nr_cell_id'], int(conf_ncell['nr_cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
self.assertEqual(p['band'], conf_ncell['nr_band'])
tdd_config = conf['nr_cell_list'][0]['tdd_ul_dl_config']['pattern1']
self.assertEqual(float(tdd_config['period']), 2.5)
self.assertEqual(int(tdd_config['dl_slots']), 3)
self.assertEqual(int(tdd_config['dl_symbols']), 10)
self.assertEqual(int(tdd_config['ul_slots']), 1)
self.assertEqual(int(tdd_config['ul_symbols']), 2)
def test_gnb_conf2(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
for p in conf['nr_cell_default']['plmn_list'][0]['nssai']:
sd = hex(p['sd'])
self.assertEqual(sd, gnb_param_dict2['nssai'][sd]['sd'], 16)
self.assertEqual(p['sst'], gnb_param_dict2['nssai'][sd]['sst'])
def test_mme_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'mme.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['plmn'], param_dict['core_network_plmn'])
def test_sim_card(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue_db.cfg'))[0]
conf = yamlpp_load(conf_file)
for n in "sim_algo imsi opc sqn impu impi".split():
self.assertEqual(conf['ue_db'][0][n], param_dict[n])
self.assertEqual(conf['ue_db'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_db'][0]['amf'], int(param_dict['amf'], 16))
p = self.requestSlaveInstance().getConnectionParameterDict()
p = p['_'] if '_' in p else p
self.assertIn('info', p)
def test_monitor_gadget_url(self):
parameters = json.loads(self.computer_partition.getConnectionParameterDict()['_'])
self.assertIn('monitor-gadget-url', parameters)
monitor_setup_url = parameters['monitor-setup-url']
monitor_gadget_url = parameters['monitor-gadget-url']
monitor_base_url = parameters['monitor-base-url']
public_url = monitor_base_url + '/public'
response = requests.get(public_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('software.cfg.html', monitor_gadget_url)
response = requests.get(monitor_gadget_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('<script src="rsvp.js"></script>', response.text)
self.assertIn('<script src="renderjs.js"></script>', response.text)
self.assertIn('<script src="g-chart.line.js"></script>', response.text)
self.assertIn('<script src="promise.gadget.js"></script>', response.text)
class TestENBParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_enb_conf(self):
test_enb_conf(self)
class TestGNBParameters1(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf1(self)
class TestGNBParameters2(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict2)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf2(self)
class TestCoreNetworkParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_mme_conf(self):
test_mme_conf(self)
def requestSlaveInstance(cls):
software_url = cls.getSoftwareURL()
return cls.slap.request(
software_release=software_url,
partition_reference="SIM-CARD",
partition_parameter_kw={'_': json.dumps(param_dict)},
shared=True,
software_type='core-network',
)
class TestENBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestGNBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestCoreNetworkMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True, 'slave-list': []})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUELTEMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUENRMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestSimCard(ORSTestCase):
@classmethod
def requestDefaultInstance(cls, state='started'):
default_instance = super(
ORSTestCase, cls).requestDefaultInstance(state=state)
cls.requestSlaveInstance()
return default_instance
@classmethod
def requestSlaveInstance(cls):
return requestSlaveInstance(cls)
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_sim_card(self):
test_sim_card(self)
class TestUELTEParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_ue_lte_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_earfcn'], param_dict['dl_earfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], 10)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
class TestUENRParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_ue_nr_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['ssb_nr_arfcn'], param_dict['ssb_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_nr_arfcn'], param_dict['dl_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], '10 MHz')
self.assertEqual(conf['cell_groups'][0]['cells'][0]['band'], param_dict['nr_band'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
##############################################################################
#
# Copyright (c) 2018 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import json
import glob
import requests
from test import yamlpp_load
from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass
setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software-fdd-ors.cfg')))
param_dict = {
'testing': True,
'sim_algo': 'milenage',
'imsi': '001010000000331',
'opc': '000102030405060708090A0B0C0D0E0F',
'amf': '0x9001',
'sqn': '000000000000',
'k': '00112233445566778899AABBCCDDEEFF',
'impu': 'impu331',
'impi': 'impi331@amarisoft.com',
'tx_gain': 17,
'rx_gain': 17,
'dl_earfcn': 325320,
'bandwidth': "10 MHz",
'enb_id': '0x17',
'pci': 250,
'tac': '0x1717',
'root_sequence_index': '1',
'mme_list': {
'10.0.0.1': {'mme_addr': '10.0.0.1'},
'2001:db8::1': {'mme_addr': '2001:db8::1'},
},
'core_network_plmn': '00102',
'dl_nr_arfcn': 325320,
'nr_band': 99,
'nr_bandwidth': 50,
'ssb_nr_arfcn': 377790,
'rue_addr': '192.168.99.88',
'n_antenna_dl': 2,
'n_antenna_ul': 2,
'inactivity_timer': 17,
'gnb_id': '0x17',
'gnb_id_bits': 30,
'ssb_pos_bitmap': '10',
'amf_list': {
'10.0.0.1': {'amf_addr': '10.0.0.1'},
'2001:db8::1': {'amf_addr': '2001:db8::1'},
},
'nr_handover_time_to_trigger': 40,
'nr_handover_a3_offset': 10,
'ncell_list': {
'ORS1': {
'dl_earfcn': 100000,
'dl_nr_arfcn': 100000,
'ssb_nr_arfcn': 100000,
'pci': 1,
'nr_cell_id': '0x0000001',
'cell_id': '0x0000001',
'gnb_id_bits': 28,
'nr_band': 1,
'tac': 1
},
'ORS2': {
'dl_earfcn': 200000,
'dl_nr_arfcn': 200000,
'ssb_nr_arfcn': 200000,
'pci': 2,
'nr_cell_id': '0x0000002',
'cell_id': '0x0000001',
'gnb_id_bits': 30,
'nr_band': 2,
'tac': 2
},
},
'xn_peers': {
'2001:db8::1': {
'xn_addr': '2001:db8::1',
},
'2001:db8::2': {
'xn_addr': '2001:db8::2',
},
},
}
enb_param_dict = {
'plmn_list': {
'00101': {'attach_without_pdn': True, 'plmn': '00101', 'reserved': True},
'00102': {'attach_without_pdn': False, 'plmn': '00102', 'reserved': False},
},
'tdd_ul_dl_config': '[Configuration 6] 5ms 5UL 3DL (maximum uplink)',
}
gnb_param_dict1 = {
'plmn_list': {
'00101': {'plmn': '00101', 'ranac': 1, 'reserved': True, 'tac': 1},
'00102': {'plmn': '00102', 'ranac': 2, 'reserved': False, 'tac': 2},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
gnb_param_dict2 = {
'nssai': {
'0x171717': {'sd': '0x171717', 'sst': 10},
'0x181818': {'sd': '0x181818', 'sst': 20},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
enb_param_dict.update(param_dict)
gnb_param_dict1.update(param_dict)
gnb_param_dict2.update(param_dict)
def test_enb_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], enb_param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], enb_param_dict['rx_gain'])
self.assertEqual(conf['cell_list'][0]['inactivity_timer'], enb_param_dict['inactivity_timer'])
self.assertNotIn('uldl_config', conf['cell_list'][0])
self.assertEqual(conf['cell_list'][0]['dl_earfcn'], enb_param_dict['dl_earfcn'])
self.assertEqual(conf['cell_list'][0]['n_rb_dl'], 50)
self.assertEqual(conf['enb_id'], int(enb_param_dict['enb_id'], 16))
self.assertEqual(conf['cell_list'][0]['n_id_cell'], enb_param_dict['pci'])
self.assertEqual(conf['cell_list'][0]['tac'], int(enb_param_dict['tac'], 16))
self.assertEqual(conf['cell_list'][0]['root_sequence_index'], int(enb_param_dict['root_sequence_index']))
self.assertEqual(conf['cell_list'][0]['cell_id'], 0)
for p in conf['cell_default']['plmn_list']:
for n in "plmn attach_without_pdn reserved".split():
self.assertEqual(p[n], enb_param_dict['plmn_list'][p['plmn']][n])
for p in conf['mme_list']:
self.assertEqual(p['mme_addr'], enb_param_dict['mme_list'][p['mme_addr']]['mme_addr'])
for p in conf['cell_list'][0]['ncell_list']:
for k in enb_param_dict['ncell_list']:
if p['dl_earfcn'] == gnb_param_dict1['ncell_list'][k]['dl_earfcn']:
break
conf_ncell = enb_param_dict['ncell_list'][k]
self.assertEqual(p['dl_earfcn'], conf_ncell['dl_earfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['cell_id'], int(conf_ncell['cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
def test_gnb_conf1(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], gnb_param_dict1['tx_gain'])
self.assertEqual(conf['rx_gain'], gnb_param_dict1['rx_gain'])
self.assertEqual(conf['nr_cell_list'][0]['inactivity_timer'], gnb_param_dict1['inactivity_timer'])
self.assertEqual(conf['nr_cell_list'][0]['dl_nr_arfcn'], gnb_param_dict1['dl_nr_arfcn'])
self.assertEqual(conf['nr_cell_list'][0]['band'], gnb_param_dict1['nr_band'])
self.assertEqual(conf['nr_cell_list'][0]['ssb_pos_bitmap'], gnb_param_dict1['ssb_pos_bitmap'])
self.assertEqual(conf['nr_cell_list'][0]['bandwidth'], gnb_param_dict1['nr_bandwidth'])
self.assertEqual(conf['nr_cell_list'][0]['n_id_cell'], gnb_param_dict1['pci'])
self.assertEqual(conf['gnb_id'], int(gnb_param_dict1['gnb_id'], 16))
self.assertEqual(conf['gnb_id_bits'], gnb_param_dict1['gnb_id_bits'])
for p in conf['nr_cell_default']['plmn_list']:
for n in "plmn ranac reserved tac".split():
self.assertEqual(p[n], gnb_param_dict1['plmn_list'][p['plmn']][n])
for p in conf['amf_list']:
self.assertEqual(p['amf_addr'], gnb_param_dict1['amf_list'][p['amf_addr']]['amf_addr'])
for p in conf['xn_peers']:
self.assertEqual(p, gnb_param_dict1['xn_peers'][p]['xn_addr'])
for p in conf['nr_cell_list'][0]['ncell_list']:
for k in gnb_param_dict1['ncell_list']:
if p['dl_nr_arfcn'] == gnb_param_dict1['ncell_list'][k]['dl_nr_arfcn']:
break
conf_ncell = gnb_param_dict1['ncell_list'][k]
self.assertEqual(p['dl_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['ssb_nr_arfcn'], conf_ncell['ssb_nr_arfcn'])
self.assertEqual(p['ul_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['gnb_id_bits'], conf_ncell['gnb_id_bits'])
self.assertEqual(p['nr_cell_id'], int(conf_ncell['nr_cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
self.assertEqual(p['band'], conf_ncell['nr_band'])
tdd_config = conf['nr_cell_list'][0]['tdd_ul_dl_config']['pattern1']
self.assertEqual(float(tdd_config['period']), 2.5)
self.assertEqual(int(tdd_config['dl_slots']), 3)
self.assertEqual(int(tdd_config['dl_symbols']), 10)
self.assertEqual(int(tdd_config['ul_slots']), 1)
self.assertEqual(int(tdd_config['ul_symbols']), 2)
def test_gnb_conf2(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
for p in conf['nr_cell_default']['plmn_list'][0]['nssai']:
sd = hex(p['sd'])
self.assertEqual(sd, gnb_param_dict2['nssai'][sd]['sd'], 16)
self.assertEqual(p['sst'], gnb_param_dict2['nssai'][sd]['sst'])
def test_mme_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'mme.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['plmn'], param_dict['core_network_plmn'])
def test_sim_card(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue_db.cfg'))[0]
conf = yamlpp_load(conf_file)
for n in "sim_algo imsi opc sqn impu impi".split():
self.assertEqual(conf['ue_db'][0][n], param_dict[n])
self.assertEqual(conf['ue_db'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_db'][0]['amf'], int(param_dict['amf'], 16))
p = self.requestSlaveInstance().getConnectionParameterDict()
p = p['_'] if '_' in p else p
self.assertIn('info', p)
def test_monitor_gadget_url(self):
parameters = json.loads(self.computer_partition.getConnectionParameterDict()['_'])
self.assertIn('monitor-gadget-url', parameters)
monitor_setup_url = parameters['monitor-setup-url']
monitor_gadget_url = parameters['monitor-gadget-url']
monitor_base_url = parameters['monitor-base-url']
public_url = monitor_base_url + '/public'
response = requests.get(public_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('software.cfg.html', monitor_gadget_url)
response = requests.get(monitor_gadget_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('<script src="rsvp.js"></script>', response.text)
self.assertIn('<script src="renderjs.js"></script>', response.text)
self.assertIn('<script src="g-chart.line.js"></script>', response.text)
self.assertIn('<script src="promise.gadget.js"></script>', response.text)
class TestENBParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_enb_conf(self):
test_enb_conf(self)
class TestGNBParameters1(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf1(self)
class TestGNBParameters2(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict2)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf2(self)
class TestCoreNetworkParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_mme_conf(self):
test_mme_conf(self)
def requestSlaveInstance(cls):
software_url = cls.getSoftwareURL()
return cls.slap.request(
software_release=software_url,
partition_reference="SIM-CARD",
partition_parameter_kw={'_': json.dumps(param_dict)},
shared=True,
software_type='core-network',
)
class TestENBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestGNBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestCoreNetworkMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True, 'slave-list': []})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUELTEMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUENRMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestSimCard(ORSTestCase):
@classmethod
def requestDefaultInstance(cls, state='started'):
default_instance = super(
ORSTestCase, cls).requestDefaultInstance(state=state)
cls.requestSlaveInstance()
return default_instance
@classmethod
def requestSlaveInstance(cls):
return requestSlaveInstance(cls)
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_sim_card(self):
test_sim_card(self)
class TestUELTEParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_ue_lte_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_earfcn'], param_dict['dl_earfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], 10)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
class TestUENRParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_ue_nr_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['ssb_nr_arfcn'], param_dict['ssb_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_nr_arfcn'], param_dict['dl_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], '10 MHz')
self.assertEqual(conf['cell_groups'][0]['cells'][0]['band'], param_dict['nr_band'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
##############################################################################
#
# Copyright (c) 2018 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import json
import glob
import requests
from test import yamlpp_load
from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass
setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software-fdd.cfg')))
param_dict = {
'testing': True,
'sim_algo': 'milenage',
'imsi': '001010000000331',
'opc': '000102030405060708090A0B0C0D0E0F',
'amf': '0x9001',
'sqn': '000000000000',
'k': '00112233445566778899AABBCCDDEEFF',
'impu': 'impu331',
'impi': 'impi331@amarisoft.com',
'tx_gain': 17,
'rx_gain': 17,
'dl_earfcn': 325320,
'bandwidth': "10 MHz",
'enb_id': '0x17',
'pci': 250,
'tac': '0x1717',
'root_sequence_index': '1',
'mme_list': {
'10.0.0.1': {'mme_addr': '10.0.0.1'},
'2001:db8::1': {'mme_addr': '2001:db8::1'},
},
'core_network_plmn': '00102',
'dl_nr_arfcn': 325320,
'nr_band': 99,
'nr_bandwidth': 50,
'ssb_nr_arfcn': 377790,
'rue_addr': '192.168.99.88',
'n_antenna_dl': 2,
'n_antenna_ul': 2,
'inactivity_timer': 17,
'gnb_id': '0x17',
'gnb_id_bits': 30,
'ssb_pos_bitmap': '10',
'amf_list': {
'10.0.0.1': {'amf_addr': '10.0.0.1'},
'2001:db8::1': {'amf_addr': '2001:db8::1'},
},
'nr_handover_time_to_trigger': 40,
'nr_handover_a3_offset': 10,
'ncell_list': {
'ORS1': {
'dl_earfcn': 100000,
'dl_nr_arfcn': 100000,
'ssb_nr_arfcn': 100000,
'pci': 1,
'nr_cell_id': '0x0000001',
'cell_id': '0x0000001',
'gnb_id_bits': 28,
'nr_band': 1,
'tac': 1
},
'ORS2': {
'dl_earfcn': 200000,
'dl_nr_arfcn': 200000,
'ssb_nr_arfcn': 200000,
'pci': 2,
'nr_cell_id': '0x0000002',
'cell_id': '0x0000001',
'gnb_id_bits': 30,
'nr_band': 2,
'tac': 2
},
},
'xn_peers': {
'2001:db8::1': {
'xn_addr': '2001:db8::1',
},
'2001:db8::2': {
'xn_addr': '2001:db8::2',
},
},
}
enb_param_dict = {
'plmn_list': {
'00101': {'attach_without_pdn': True, 'plmn': '00101', 'reserved': True},
'00102': {'attach_without_pdn': False, 'plmn': '00102', 'reserved': False},
},
'tdd_ul_dl_config': '[Configuration 6] 5ms 5UL 3DL (maximum uplink)',
}
gnb_param_dict1 = {
'plmn_list': {
'00101': {'plmn': '00101', 'ranac': 1, 'reserved': True, 'tac': 1},
'00102': {'plmn': '00102', 'ranac': 2, 'reserved': False, 'tac': 2},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
gnb_param_dict2 = {
'nssai': {
'0x171717': {'sd': '0x171717', 'sst': 10},
'0x181818': {'sd': '0x181818', 'sst': 20},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
enb_param_dict.update(param_dict)
gnb_param_dict1.update(param_dict)
gnb_param_dict2.update(param_dict)
def test_enb_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], enb_param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], enb_param_dict['rx_gain'])
self.assertEqual(conf['cell_list'][0]['inactivity_timer'], enb_param_dict['inactivity_timer'])
self.assertNotIn('uldl_config', conf['cell_list'][0])
self.assertEqual(conf['cell_list'][0]['dl_earfcn'], enb_param_dict['dl_earfcn'])
self.assertEqual(conf['cell_list'][0]['n_rb_dl'], 50)
self.assertEqual(conf['enb_id'], int(enb_param_dict['enb_id'], 16))
self.assertEqual(conf['cell_list'][0]['n_id_cell'], enb_param_dict['pci'])
self.assertEqual(conf['cell_list'][0]['tac'], int(enb_param_dict['tac'], 16))
self.assertEqual(conf['cell_list'][0]['root_sequence_index'], int(enb_param_dict['root_sequence_index']))
self.assertEqual(conf['cell_list'][0]['cell_id'], 0)
for p in conf['cell_default']['plmn_list']:
for n in "plmn attach_without_pdn reserved".split():
self.assertEqual(p[n], enb_param_dict['plmn_list'][p['plmn']][n])
for p in conf['mme_list']:
self.assertEqual(p['mme_addr'], enb_param_dict['mme_list'][p['mme_addr']]['mme_addr'])
for p in conf['cell_list'][0]['ncell_list']:
for k in enb_param_dict['ncell_list']:
if p['dl_earfcn'] == gnb_param_dict1['ncell_list'][k]['dl_earfcn']:
break
conf_ncell = enb_param_dict['ncell_list'][k]
self.assertEqual(p['dl_earfcn'], conf_ncell['dl_earfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['cell_id'], int(conf_ncell['cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
def test_gnb_conf1(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], gnb_param_dict1['tx_gain'])
self.assertEqual(conf['rx_gain'], gnb_param_dict1['rx_gain'])
self.assertEqual(conf['nr_cell_list'][0]['inactivity_timer'], gnb_param_dict1['inactivity_timer'])
self.assertEqual(conf['nr_cell_list'][0]['dl_nr_arfcn'], gnb_param_dict1['dl_nr_arfcn'])
self.assertEqual(conf['nr_cell_list'][0]['band'], gnb_param_dict1['nr_band'])
self.assertEqual(conf['nr_cell_list'][0]['ssb_pos_bitmap'], gnb_param_dict1['ssb_pos_bitmap'])
self.assertEqual(conf['nr_cell_list'][0]['bandwidth'], gnb_param_dict1['nr_bandwidth'])
self.assertEqual(conf['nr_cell_list'][0]['n_id_cell'], gnb_param_dict1['pci'])
self.assertEqual(conf['gnb_id'], int(gnb_param_dict1['gnb_id'], 16))
self.assertEqual(conf['gnb_id_bits'], gnb_param_dict1['gnb_id_bits'])
for p in conf['nr_cell_default']['plmn_list']:
for n in "plmn ranac reserved tac".split():
self.assertEqual(p[n], gnb_param_dict1['plmn_list'][p['plmn']][n])
for p in conf['amf_list']:
self.assertEqual(p['amf_addr'], gnb_param_dict1['amf_list'][p['amf_addr']]['amf_addr'])
for p in conf['xn_peers']:
self.assertEqual(p, gnb_param_dict1['xn_peers'][p]['xn_addr'])
for p in conf['nr_cell_list'][0]['ncell_list']:
for k in gnb_param_dict1['ncell_list']:
if p['dl_nr_arfcn'] == gnb_param_dict1['ncell_list'][k]['dl_nr_arfcn']:
break
conf_ncell = gnb_param_dict1['ncell_list'][k]
self.assertEqual(p['dl_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['ssb_nr_arfcn'], conf_ncell['ssb_nr_arfcn'])
self.assertEqual(p['ul_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['gnb_id_bits'], conf_ncell['gnb_id_bits'])
self.assertEqual(p['nr_cell_id'], int(conf_ncell['nr_cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
self.assertEqual(p['band'], conf_ncell['nr_band'])
tdd_config = conf['nr_cell_list'][0]['tdd_ul_dl_config']['pattern1']
self.assertEqual(float(tdd_config['period']), 2.5)
self.assertEqual(int(tdd_config['dl_slots']), 3)
self.assertEqual(int(tdd_config['dl_symbols']), 10)
self.assertEqual(int(tdd_config['ul_slots']), 1)
self.assertEqual(int(tdd_config['ul_symbols']), 2)
def test_gnb_conf2(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
for p in conf['nr_cell_default']['plmn_list'][0]['nssai']:
sd = hex(p['sd'])
self.assertEqual(sd, gnb_param_dict2['nssai'][sd]['sd'], 16)
self.assertEqual(p['sst'], gnb_param_dict2['nssai'][sd]['sst'])
def test_mme_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'mme.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['plmn'], param_dict['core_network_plmn'])
def test_sim_card(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue_db.cfg'))[0]
conf = yamlpp_load(conf_file)
for n in "sim_algo imsi opc sqn impu impi".split():
self.assertEqual(conf['ue_db'][0][n], param_dict[n])
self.assertEqual(conf['ue_db'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_db'][0]['amf'], int(param_dict['amf'], 16))
p = self.requestSlaveInstance().getConnectionParameterDict()
p = p['_'] if '_' in p else p
self.assertIn('info', p)
def test_monitor_gadget_url(self):
parameters = json.loads(self.computer_partition.getConnectionParameterDict()['_'])
self.assertIn('monitor-gadget-url', parameters)
monitor_setup_url = parameters['monitor-setup-url']
monitor_gadget_url = parameters['monitor-gadget-url']
monitor_base_url = parameters['monitor-base-url']
public_url = monitor_base_url + '/public'
response = requests.get(public_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('software.cfg.html', monitor_gadget_url)
response = requests.get(monitor_gadget_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('<script src="rsvp.js"></script>', response.text)
self.assertIn('<script src="renderjs.js"></script>', response.text)
self.assertIn('<script src="g-chart.line.js"></script>', response.text)
self.assertIn('<script src="promise.gadget.js"></script>', response.text)
class TestENBParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_enb_conf(self):
test_enb_conf(self)
class TestGNBParameters1(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf1(self)
class TestGNBParameters2(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict2)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf2(self)
class TestCoreNetworkParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_mme_conf(self):
test_mme_conf(self)
def requestSlaveInstance(cls):
software_url = cls.getSoftwareURL()
return cls.slap.request(
software_release=software_url,
partition_reference="SIM-CARD",
partition_parameter_kw={'_': json.dumps(param_dict)},
shared=True,
software_type='core-network',
)
class TestENBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestGNBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestCoreNetworkMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True, 'slave-list': []})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUELTEMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUENRMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestSimCard(ORSTestCase):
@classmethod
def requestDefaultInstance(cls, state='started'):
default_instance = super(
ORSTestCase, cls).requestDefaultInstance(state=state)
cls.requestSlaveInstance()
return default_instance
@classmethod
def requestSlaveInstance(cls):
return requestSlaveInstance(cls)
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_sim_card(self):
test_sim_card(self)
class TestUELTEParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_ue_lte_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_earfcn'], param_dict['dl_earfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], 10)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
class TestUENRParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_ue_nr_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['ssb_nr_arfcn'], param_dict['ssb_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_nr_arfcn'], param_dict['dl_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], '10 MHz')
self.assertEqual(conf['cell_groups'][0]['cells'][0]['band'], param_dict['nr_band'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
##############################################################################
#
# Copyright (c) 2018 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import json
import glob
import requests
from test import yamlpp_load
from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass
setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software-tdd-m2ru.cfg')))
param_dict = {
'testing': True,
'sim_algo': 'milenage',
'imsi': '001010000000331',
'opc': '000102030405060708090A0B0C0D0E0F',
'amf': '0x9001',
'sqn': '000000000000',
'k': '00112233445566778899AABBCCDDEEFF',
'impu': 'impu331',
'impi': 'impi331@amarisoft.com',
'tx_gain': 17,
'rx_gain': 17,
'dl_earfcn': 325320,
'bandwidth': "10 MHz",
'enb_id': '0x17',
'pci': 250,
'tac': '0x1717',
'root_sequence_index': '1',
'mme_list': {
'10.0.0.1': {'mme_addr': '10.0.0.1'},
'2001:db8::1': {'mme_addr': '2001:db8::1'},
},
'core_network_plmn': '00102',
'dl_nr_arfcn': 325320,
'nr_band': 99,
'nr_bandwidth': 50,
'ssb_nr_arfcn': 377790,
'rue_addr': '192.168.99.88',
'n_antenna_dl': 2,
'n_antenna_ul': 2,
'inactivity_timer': 17,
'gnb_id': '0x17',
'gnb_id_bits': 30,
'ssb_pos_bitmap': '10',
'amf_list': {
'10.0.0.1': {'amf_addr': '10.0.0.1'},
'2001:db8::1': {'amf_addr': '2001:db8::1'},
},
'nr_handover_time_to_trigger': 40,
'nr_handover_a3_offset': 10,
'ncell_list': {
'ORS1': {
'dl_earfcn': 100000,
'dl_nr_arfcn': 100000,
'ssb_nr_arfcn': 100000,
'pci': 1,
'nr_cell_id': '0x0000001',
'cell_id': '0x0000001',
'gnb_id_bits': 28,
'nr_band': 1,
'tac': 1
},
'ORS2': {
'dl_earfcn': 200000,
'dl_nr_arfcn': 200000,
'ssb_nr_arfcn': 200000,
'pci': 2,
'nr_cell_id': '0x0000002',
'cell_id': '0x0000001',
'gnb_id_bits': 30,
'nr_band': 2,
'tac': 2
},
},
'xn_peers': {
'2001:db8::1': {
'xn_addr': '2001:db8::1',
},
'2001:db8::2': {
'xn_addr': '2001:db8::2',
},
},
}
enb_param_dict = {
'plmn_list': {
'00101': {'attach_without_pdn': True, 'plmn': '00101', 'reserved': True},
'00102': {'attach_without_pdn': False, 'plmn': '00102', 'reserved': False},
},
'tdd_ul_dl_config': '[Configuration 6] 5ms 5UL 3DL (maximum uplink)',
}
gnb_param_dict1 = {
'plmn_list': {
'00101': {'plmn': '00101', 'ranac': 1, 'reserved': True, 'tac': 1},
'00102': {'plmn': '00102', 'ranac': 2, 'reserved': False, 'tac': 2},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
gnb_param_dict2 = {
'nssai': {
'0x171717': {'sd': '0x171717', 'sst': 10},
'0x181818': {'sd': '0x181818', 'sst': 20},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
enb_param_dict.update(param_dict)
gnb_param_dict1.update(param_dict)
gnb_param_dict2.update(param_dict)
def test_enb_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], enb_param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], enb_param_dict['rx_gain'])
self.assertEqual(conf['cell_list'][0]['inactivity_timer'], enb_param_dict['inactivity_timer'])
self.assertEqual(conf['cell_list'][0]['uldl_config'], 6)
self.assertEqual(conf['cell_list'][0]['dl_earfcn'], enb_param_dict['dl_earfcn'])
self.assertEqual(conf['cell_list'][0]['n_rb_dl'], 50)
self.assertEqual(conf['enb_id'], int(enb_param_dict['enb_id'], 16))
self.assertEqual(conf['cell_list'][0]['n_id_cell'], enb_param_dict['pci'])
self.assertEqual(conf['cell_list'][0]['tac'], int(enb_param_dict['tac'], 16))
self.assertEqual(conf['cell_list'][0]['root_sequence_index'], int(enb_param_dict['root_sequence_index']))
self.assertEqual(conf['cell_list'][0]['cell_id'], 0)
for p in conf['cell_default']['plmn_list']:
for n in "plmn attach_without_pdn reserved".split():
self.assertEqual(p[n], enb_param_dict['plmn_list'][p['plmn']][n])
for p in conf['mme_list']:
self.assertEqual(p['mme_addr'], enb_param_dict['mme_list'][p['mme_addr']]['mme_addr'])
for p in conf['cell_list'][0]['ncell_list']:
for k in enb_param_dict['ncell_list']:
if p['dl_earfcn'] == gnb_param_dict1['ncell_list'][k]['dl_earfcn']:
break
conf_ncell = enb_param_dict['ncell_list'][k]
self.assertEqual(p['dl_earfcn'], conf_ncell['dl_earfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['cell_id'], int(conf_ncell['cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
def test_gnb_conf1(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], gnb_param_dict1['tx_gain'])
self.assertEqual(conf['rx_gain'], gnb_param_dict1['rx_gain'])
self.assertEqual(conf['nr_cell_list'][0]['inactivity_timer'], gnb_param_dict1['inactivity_timer'])
self.assertEqual(conf['nr_cell_list'][0]['dl_nr_arfcn'], gnb_param_dict1['dl_nr_arfcn'])
self.assertEqual(conf['nr_cell_list'][0]['band'], gnb_param_dict1['nr_band'])
self.assertEqual(conf['nr_cell_list'][0]['ssb_pos_bitmap'], gnb_param_dict1['ssb_pos_bitmap'])
self.assertEqual(conf['nr_cell_list'][0]['bandwidth'], gnb_param_dict1['nr_bandwidth'])
self.assertEqual(conf['nr_cell_list'][0]['n_id_cell'], gnb_param_dict1['pci'])
self.assertEqual(conf['gnb_id'], int(gnb_param_dict1['gnb_id'], 16))
self.assertEqual(conf['gnb_id_bits'], gnb_param_dict1['gnb_id_bits'])
for p in conf['nr_cell_default']['plmn_list']:
for n in "plmn ranac reserved tac".split():
self.assertEqual(p[n], gnb_param_dict1['plmn_list'][p['plmn']][n])
for p in conf['amf_list']:
self.assertEqual(p['amf_addr'], gnb_param_dict1['amf_list'][p['amf_addr']]['amf_addr'])
for p in conf['xn_peers']:
self.assertEqual(p, gnb_param_dict1['xn_peers'][p]['xn_addr'])
for p in conf['nr_cell_list'][0]['ncell_list']:
for k in gnb_param_dict1['ncell_list']:
if p['dl_nr_arfcn'] == gnb_param_dict1['ncell_list'][k]['dl_nr_arfcn']:
break
conf_ncell = gnb_param_dict1['ncell_list'][k]
self.assertEqual(p['dl_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['ssb_nr_arfcn'], conf_ncell['ssb_nr_arfcn'])
self.assertEqual(p['ul_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['gnb_id_bits'], conf_ncell['gnb_id_bits'])
self.assertEqual(p['nr_cell_id'], int(conf_ncell['nr_cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
self.assertEqual(p['band'], conf_ncell['nr_band'])
tdd_config = conf['nr_cell_list'][0]['tdd_ul_dl_config']['pattern1']
self.assertEqual(float(tdd_config['period']), 2.5)
self.assertEqual(int(tdd_config['dl_slots']), 3)
self.assertEqual(int(tdd_config['dl_symbols']), 10)
self.assertEqual(int(tdd_config['ul_slots']), 1)
self.assertEqual(int(tdd_config['ul_symbols']), 2)
def test_gnb_conf2(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
for p in conf['nr_cell_default']['plmn_list'][0]['nssai']:
sd = hex(p['sd'])
self.assertEqual(sd, gnb_param_dict2['nssai'][sd]['sd'], 16)
self.assertEqual(p['sst'], gnb_param_dict2['nssai'][sd]['sst'])
def test_mme_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'mme.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['plmn'], param_dict['core_network_plmn'])
def test_sim_card(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue_db.cfg'))[0]
conf = yamlpp_load(conf_file)
for n in "sim_algo imsi opc sqn impu impi".split():
self.assertEqual(conf['ue_db'][0][n], param_dict[n])
self.assertEqual(conf['ue_db'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_db'][0]['amf'], int(param_dict['amf'], 16))
p = self.requestSlaveInstance().getConnectionParameterDict()
p = p['_'] if '_' in p else p
self.assertIn('info', p)
def test_monitor_gadget_url(self):
parameters = json.loads(self.computer_partition.getConnectionParameterDict()['_'])
self.assertIn('monitor-gadget-url', parameters)
monitor_setup_url = parameters['monitor-setup-url']
monitor_gadget_url = parameters['monitor-gadget-url']
monitor_base_url = parameters['monitor-base-url']
public_url = monitor_base_url + '/public'
response = requests.get(public_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('software.cfg.html', monitor_gadget_url)
response = requests.get(monitor_gadget_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('<script src="rsvp.js"></script>', response.text)
self.assertIn('<script src="renderjs.js"></script>', response.text)
self.assertIn('<script src="g-chart.line.js"></script>', response.text)
self.assertIn('<script src="promise.gadget.js"></script>', response.text)
class TestENBParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_enb_conf(self):
test_enb_conf(self)
class TestGNBParameters1(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf1(self)
class TestGNBParameters2(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict2)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf2(self)
class TestCoreNetworkParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_mme_conf(self):
test_mme_conf(self)
def requestSlaveInstance(cls):
software_url = cls.getSoftwareURL()
return cls.slap.request(
software_release=software_url,
partition_reference="SIM-CARD",
partition_parameter_kw={'_': json.dumps(param_dict)},
shared=True,
software_type='core-network',
)
class TestENBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestGNBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestCoreNetworkMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True, 'slave-list': []})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUELTEMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUENRMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestSimCard(ORSTestCase):
@classmethod
def requestDefaultInstance(cls, state='started'):
default_instance = super(
ORSTestCase, cls).requestDefaultInstance(state=state)
cls.requestSlaveInstance()
return default_instance
@classmethod
def requestSlaveInstance(cls):
return requestSlaveInstance(cls)
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_sim_card(self):
test_sim_card(self)
class TestUELTEParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_ue_lte_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_earfcn'], param_dict['dl_earfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], 10)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
class TestUENRParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_ue_nr_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['ssb_nr_arfcn'], param_dict['ssb_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_nr_arfcn'], param_dict['dl_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], '10 MHz')
self.assertEqual(conf['cell_groups'][0]['cells'][0]['band'], param_dict['nr_band'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
##############################################################################
#
# Copyright (c) 2018 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import json
import glob
import requests
from test import yamlpp_load
from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass
setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software-tdd-ors.cfg')))
param_dict = {
'testing': True,
'sim_algo': 'milenage',
'imsi': '001010000000331',
'opc': '000102030405060708090A0B0C0D0E0F',
'amf': '0x9001',
'sqn': '000000000000',
'k': '00112233445566778899AABBCCDDEEFF',
'impu': 'impu331',
'impi': 'impi331@amarisoft.com',
'tx_gain': 17,
'rx_gain': 17,
'dl_earfcn': 325320,
'bandwidth': "10 MHz",
'enb_id': '0x17',
'pci': 250,
'tac': '0x1717',
'root_sequence_index': '1',
'mme_list': {
'10.0.0.1': {'mme_addr': '10.0.0.1'},
'2001:db8::1': {'mme_addr': '2001:db8::1'},
},
'core_network_plmn': '00102',
'dl_nr_arfcn': 325320,
'nr_band': 99,
'nr_bandwidth': 50,
'ssb_nr_arfcn': 377790,
'rue_addr': '192.168.99.88',
'n_antenna_dl': 2,
'n_antenna_ul': 2,
'inactivity_timer': 17,
'gnb_id': '0x17',
'gnb_id_bits': 30,
'ssb_pos_bitmap': '10',
'amf_list': {
'10.0.0.1': {'amf_addr': '10.0.0.1'},
'2001:db8::1': {'amf_addr': '2001:db8::1'},
},
'nr_handover_time_to_trigger': 40,
'nr_handover_a3_offset': 10,
'ncell_list': {
'ORS1': {
'dl_earfcn': 100000,
'dl_nr_arfcn': 100000,
'ssb_nr_arfcn': 100000,
'pci': 1,
'nr_cell_id': '0x0000001',
'cell_id': '0x0000001',
'gnb_id_bits': 28,
'nr_band': 1,
'tac': 1
},
'ORS2': {
'dl_earfcn': 200000,
'dl_nr_arfcn': 200000,
'ssb_nr_arfcn': 200000,
'pci': 2,
'nr_cell_id': '0x0000002',
'cell_id': '0x0000001',
'gnb_id_bits': 30,
'nr_band': 2,
'tac': 2
},
},
'xn_peers': {
'2001:db8::1': {
'xn_addr': '2001:db8::1',
},
'2001:db8::2': {
'xn_addr': '2001:db8::2',
},
},
}
enb_param_dict = {
'plmn_list': {
'00101': {'attach_without_pdn': True, 'plmn': '00101', 'reserved': True},
'00102': {'attach_without_pdn': False, 'plmn': '00102', 'reserved': False},
},
'tdd_ul_dl_config': '[Configuration 6] 5ms 5UL 3DL (maximum uplink)',
}
gnb_param_dict1 = {
'plmn_list': {
'00101': {'plmn': '00101', 'ranac': 1, 'reserved': True, 'tac': 1},
'00102': {'plmn': '00102', 'ranac': 2, 'reserved': False, 'tac': 2},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
gnb_param_dict2 = {
'nssai': {
'0x171717': {'sd': '0x171717', 'sst': 10},
'0x181818': {'sd': '0x181818', 'sst': 20},
},
'tdd_ul_dl_config': '2.5ms 1UL 3DL 2/10',
}
enb_param_dict.update(param_dict)
gnb_param_dict1.update(param_dict)
gnb_param_dict2.update(param_dict)
def test_enb_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], enb_param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], enb_param_dict['rx_gain'])
self.assertEqual(conf['cell_list'][0]['inactivity_timer'], enb_param_dict['inactivity_timer'])
self.assertEqual(conf['cell_list'][0]['uldl_config'], 6)
self.assertEqual(conf['cell_list'][0]['dl_earfcn'], enb_param_dict['dl_earfcn'])
self.assertEqual(conf['cell_list'][0]['n_rb_dl'], 50)
self.assertEqual(conf['enb_id'], int(enb_param_dict['enb_id'], 16))
self.assertEqual(conf['cell_list'][0]['n_id_cell'], enb_param_dict['pci'])
self.assertEqual(conf['cell_list'][0]['tac'], int(enb_param_dict['tac'], 16))
self.assertEqual(conf['cell_list'][0]['root_sequence_index'], int(enb_param_dict['root_sequence_index']))
self.assertEqual(conf['cell_list'][0]['cell_id'], 0)
for p in conf['cell_default']['plmn_list']:
for n in "plmn attach_without_pdn reserved".split():
self.assertEqual(p[n], enb_param_dict['plmn_list'][p['plmn']][n])
for p in conf['mme_list']:
self.assertEqual(p['mme_addr'], enb_param_dict['mme_list'][p['mme_addr']]['mme_addr'])
for p in conf['cell_list'][0]['ncell_list']:
for k in enb_param_dict['ncell_list']:
if p['dl_earfcn'] == gnb_param_dict1['ncell_list'][k]['dl_earfcn']:
break
conf_ncell = enb_param_dict['ncell_list'][k]
self.assertEqual(p['dl_earfcn'], conf_ncell['dl_earfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['cell_id'], int(conf_ncell['cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
def test_gnb_conf1(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf:
self.assertEqual(conf['tx_gain'], gnb_param_dict1['tx_gain'])
self.assertEqual(conf['rx_gain'], gnb_param_dict1['rx_gain'])
self.assertEqual(conf['nr_cell_list'][0]['inactivity_timer'], gnb_param_dict1['inactivity_timer'])
self.assertEqual(conf['nr_cell_list'][0]['dl_nr_arfcn'], gnb_param_dict1['dl_nr_arfcn'])
self.assertEqual(conf['nr_cell_list'][0]['band'], gnb_param_dict1['nr_band'])
self.assertEqual(conf['nr_cell_list'][0]['ssb_pos_bitmap'], gnb_param_dict1['ssb_pos_bitmap'])
self.assertEqual(conf['nr_cell_list'][0]['bandwidth'], gnb_param_dict1['nr_bandwidth'])
self.assertEqual(conf['nr_cell_list'][0]['n_id_cell'], gnb_param_dict1['pci'])
self.assertEqual(conf['gnb_id'], int(gnb_param_dict1['gnb_id'], 16))
self.assertEqual(conf['gnb_id_bits'], gnb_param_dict1['gnb_id_bits'])
for p in conf['nr_cell_default']['plmn_list']:
for n in "plmn ranac reserved tac".split():
self.assertEqual(p[n], gnb_param_dict1['plmn_list'][p['plmn']][n])
for p in conf['amf_list']:
self.assertEqual(p['amf_addr'], gnb_param_dict1['amf_list'][p['amf_addr']]['amf_addr'])
for p in conf['xn_peers']:
self.assertEqual(p, gnb_param_dict1['xn_peers'][p]['xn_addr'])
for p in conf['nr_cell_list'][0]['ncell_list']:
for k in gnb_param_dict1['ncell_list']:
if p['dl_nr_arfcn'] == gnb_param_dict1['ncell_list'][k]['dl_nr_arfcn']:
break
conf_ncell = gnb_param_dict1['ncell_list'][k]
self.assertEqual(p['dl_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['ssb_nr_arfcn'], conf_ncell['ssb_nr_arfcn'])
self.assertEqual(p['ul_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['gnb_id_bits'], conf_ncell['gnb_id_bits'])
self.assertEqual(p['nr_cell_id'], int(conf_ncell['nr_cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
self.assertEqual(p['band'], conf_ncell['nr_band'])
tdd_config = conf['nr_cell_list'][0]['tdd_ul_dl_config']['pattern1']
self.assertEqual(float(tdd_config['period']), 2.5)
self.assertEqual(int(tdd_config['dl_slots']), 3)
self.assertEqual(int(tdd_config['dl_symbols']), 10)
self.assertEqual(int(tdd_config['ul_slots']), 1)
self.assertEqual(int(tdd_config['ul_symbols']), 2)
def test_gnb_conf2(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file)
for p in conf['nr_cell_default']['plmn_list'][0]['nssai']:
sd = hex(p['sd'])
self.assertEqual(sd, gnb_param_dict2['nssai'][sd]['sd'], 16)
self.assertEqual(p['sst'], gnb_param_dict2['nssai'][sd]['sst'])
def test_mme_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'mme.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['plmn'], param_dict['core_network_plmn'])
def test_sim_card(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue_db.cfg'))[0]
conf = yamlpp_load(conf_file)
for n in "sim_algo imsi opc sqn impu impi".split():
self.assertEqual(conf['ue_db'][0][n], param_dict[n])
self.assertEqual(conf['ue_db'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_db'][0]['amf'], int(param_dict['amf'], 16))
p = self.requestSlaveInstance().getConnectionParameterDict()
p = p['_'] if '_' in p else p
self.assertIn('info', p)
def test_monitor_gadget_url(self):
parameters = json.loads(self.computer_partition.getConnectionParameterDict()['_'])
self.assertIn('monitor-gadget-url', parameters)
monitor_setup_url = parameters['monitor-setup-url']
monitor_gadget_url = parameters['monitor-gadget-url']
monitor_base_url = parameters['monitor-base-url']
public_url = monitor_base_url + '/public'
response = requests.get(public_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('software.cfg.html', monitor_gadget_url)
response = requests.get(monitor_gadget_url, verify=False)
self.assertEqual(requests.codes['OK'], response.status_code)
self.assertIn('<script src="rsvp.js"></script>', response.text)
self.assertIn('<script src="renderjs.js"></script>', response.text)
self.assertIn('<script src="g-chart.line.js"></script>', response.text)
self.assertIn('<script src="promise.gadget.js"></script>', response.text)
class TestENBParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_enb_conf(self):
test_enb_conf(self)
class TestGNBParameters1(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf1(self)
class TestGNBParameters2(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict2)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf2(self)
class TestCoreNetworkParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_mme_conf(self):
test_mme_conf(self)
def requestSlaveInstance(cls):
software_url = cls.getSoftwareURL()
return cls.slap.request(
software_release=software_url,
partition_reference="SIM-CARD",
partition_parameter_kw={'_': json.dumps(param_dict)},
shared=True,
software_type='core-network',
)
class TestENBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestGNBMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestCoreNetworkMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True, 'slave-list': []})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUELTEMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUENRMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestSimCard(ORSTestCase):
@classmethod
def requestDefaultInstance(cls, state='started'):
default_instance = super(
ORSTestCase, cls).requestDefaultInstance(state=state)
cls.requestSlaveInstance()
return default_instance
@classmethod
def requestSlaveInstance(cls):
return requestSlaveInstance(cls)
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_sim_card(self):
test_sim_card(self)
class TestUELTEParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_ue_lte_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_earfcn'], param_dict['dl_earfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], 10)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
class TestUENRParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_ue_nr_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['ssb_nr_arfcn'], param_dict['ssb_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_nr_arfcn'], param_dict['dl_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], '10 MHz')
self.assertEqual(conf['cell_groups'][0]['cells'][0]['band'], param_dict['nr_band'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
...@@ -36,7 +36,7 @@ from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass ...@@ -36,7 +36,7 @@ from slapos.testing.testcase import makeModuleSetUpAndTestCaseClass
setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass( setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass(
os.path.abspath( os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software-tdd.cfg'))) os.path.join(os.path.dirname(__file__), '..', 'software-ors.cfg')))
param_dict = { param_dict = {
'testing': True, 'testing': True,
...@@ -50,7 +50,7 @@ param_dict = { ...@@ -50,7 +50,7 @@ param_dict = {
'impi': 'impi331@amarisoft.com', 'impi': 'impi331@amarisoft.com',
'tx_gain': 17, 'tx_gain': 17,
'rx_gain': 17, 'rx_gain': 17,
'dl_earfcn': 325320, 'dl_earfcn': 36100,
'bandwidth': "10 MHz", 'bandwidth': "10 MHz",
'enb_id': '0x17', 'enb_id': '0x17',
'pci': 250, 'pci': 250,
...@@ -61,10 +61,10 @@ param_dict = { ...@@ -61,10 +61,10 @@ param_dict = {
'2001:db8::1': {'mme_addr': '2001:db8::1'}, '2001:db8::1': {'mme_addr': '2001:db8::1'},
}, },
'core_network_plmn': '00102', 'core_network_plmn': '00102',
'dl_nr_arfcn': 325320, 'dl_nr_arfcn': 403500,
'nr_band': 99, 'nr_band': 34,
'nr_bandwidth': 50, 'nr_bandwidth': 50,
'ssb_nr_arfcn': 377790, 'ssb_nr_arfcn': 403520,
'rue_addr': '192.168.99.88', 'rue_addr': '192.168.99.88',
'n_antenna_dl': 2, 'n_antenna_dl': 2,
'n_antenna_ul': 2, 'n_antenna_ul': 2,
...@@ -80,25 +80,25 @@ param_dict = { ...@@ -80,25 +80,25 @@ param_dict = {
'nr_handover_a3_offset': 10, 'nr_handover_a3_offset': 10,
'ncell_list': { 'ncell_list': {
'ORS1': { 'ORS1': {
'dl_earfcn': 100000, 'dl_earfcn': 40000,
'dl_nr_arfcn': 100000, 'dl_nr_arfcn': 403500,
'ssb_nr_arfcn': 100000, 'ssb_nr_arfcn': 403500,
'pci': 1, 'pci': 1,
'nr_cell_id': '0x0000001', 'nr_cell_id': '0x0000001',
'cell_id': '0x0000001', 'cell_id': '0x0000001',
'gnb_id_bits': 28, 'gnb_id_bits': 28,
'nr_band': 1, 'nr_band': 34,
'tac': 1 'tac': 1
}, },
'ORS2': { 'ORS2': {
'dl_earfcn': 200000, 'dl_earfcn': 50000,
'dl_nr_arfcn': 200000, 'dl_nr_arfcn': 519000,
'ssb_nr_arfcn': 200000, 'ssb_nr_arfcn': 519000,
'pci': 2, 'pci': 2,
'nr_cell_id': '0x0000002', 'nr_cell_id': '0x0000002',
'cell_id': '0x0000001', 'cell_id': '0x0000001',
'gnb_id_bits': 30, 'gnb_id_bits': 30,
'nr_band': 2, 'nr_band': 38,
'tac': 2 'tac': 2
}, },
}, },
...@@ -142,9 +142,8 @@ def test_enb_conf(self): ...@@ -142,9 +142,8 @@ def test_enb_conf(self):
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0] self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file) conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf: self.assertEqual(conf['tx_gain'], [enb_param_dict['tx_gain']] * enb_param_dict['n_antenna_dl'])
self.assertEqual(conf['tx_gain'], enb_param_dict['tx_gain']) self.assertEqual(conf['rx_gain'], [enb_param_dict['rx_gain']] * enb_param_dict['n_antenna_ul'])
self.assertEqual(conf['rx_gain'], enb_param_dict['rx_gain'])
self.assertEqual(conf['cell_list'][0]['inactivity_timer'], enb_param_dict['inactivity_timer']) self.assertEqual(conf['cell_list'][0]['inactivity_timer'], enb_param_dict['inactivity_timer'])
self.assertEqual(conf['cell_list'][0]['uldl_config'], 6) self.assertEqual(conf['cell_list'][0]['uldl_config'], 6)
self.assertEqual(conf['cell_list'][0]['dl_earfcn'], enb_param_dict['dl_earfcn']) self.assertEqual(conf['cell_list'][0]['dl_earfcn'], enb_param_dict['dl_earfcn'])
...@@ -153,7 +152,7 @@ def test_enb_conf(self): ...@@ -153,7 +152,7 @@ def test_enb_conf(self):
self.assertEqual(conf['cell_list'][0]['n_id_cell'], enb_param_dict['pci']) self.assertEqual(conf['cell_list'][0]['n_id_cell'], enb_param_dict['pci'])
self.assertEqual(conf['cell_list'][0]['tac'], int(enb_param_dict['tac'], 16)) self.assertEqual(conf['cell_list'][0]['tac'], int(enb_param_dict['tac'], 16))
self.assertEqual(conf['cell_list'][0]['root_sequence_index'], int(enb_param_dict['root_sequence_index'])) self.assertEqual(conf['cell_list'][0]['root_sequence_index'], int(enb_param_dict['root_sequence_index']))
self.assertEqual(conf['cell_list'][0]['cell_id'], 0) self.assertEqual(conf['cell_list'][0]['cell_id'], 1)
for p in conf['cell_default']['plmn_list']: for p in conf['cell_default']['plmn_list']:
for n in "plmn attach_without_pdn reserved".split(): for n in "plmn attach_without_pdn reserved".split():
self.assertEqual(p[n], enb_param_dict['plmn_list'][p['plmn']][n]) self.assertEqual(p[n], enb_param_dict['plmn_list'][p['plmn']][n])
...@@ -176,9 +175,8 @@ def test_gnb_conf1(self): ...@@ -176,9 +175,8 @@ def test_gnb_conf1(self):
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0] self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
conf = yamlpp_load(conf_file) conf = yamlpp_load(conf_file)
if 'tx_gain' in conf and 'rx_gain' in conf: self.assertEqual(conf['tx_gain'], [gnb_param_dict1['tx_gain']] * gnb_param_dict1['n_antenna_dl'])
self.assertEqual(conf['tx_gain'], gnb_param_dict1['tx_gain']) self.assertEqual(conf['rx_gain'], [gnb_param_dict1['rx_gain']] * gnb_param_dict1['n_antenna_ul'])
self.assertEqual(conf['rx_gain'], gnb_param_dict1['rx_gain'])
self.assertEqual(conf['nr_cell_list'][0]['inactivity_timer'], gnb_param_dict1['inactivity_timer']) self.assertEqual(conf['nr_cell_list'][0]['inactivity_timer'], gnb_param_dict1['inactivity_timer'])
self.assertEqual(conf['nr_cell_list'][0]['dl_nr_arfcn'], gnb_param_dict1['dl_nr_arfcn']) self.assertEqual(conf['nr_cell_list'][0]['dl_nr_arfcn'], gnb_param_dict1['dl_nr_arfcn'])
self.assertEqual(conf['nr_cell_list'][0]['band'], gnb_param_dict1['nr_band']) self.assertEqual(conf['nr_cell_list'][0]['band'], gnb_param_dict1['nr_band'])
...@@ -201,7 +199,7 @@ def test_gnb_conf1(self): ...@@ -201,7 +199,7 @@ def test_gnb_conf1(self):
conf_ncell = gnb_param_dict1['ncell_list'][k] conf_ncell = gnb_param_dict1['ncell_list'][k]
self.assertEqual(p['dl_nr_arfcn'], conf_ncell['dl_nr_arfcn']) self.assertEqual(p['dl_nr_arfcn'], conf_ncell['dl_nr_arfcn'])
self.assertEqual(p['ssb_nr_arfcn'], conf_ncell['ssb_nr_arfcn']) self.assertEqual(p['ssb_nr_arfcn'], conf_ncell['ssb_nr_arfcn'])
self.assertEqual(p['ul_nr_arfcn'], conf_ncell['dl_nr_arfcn']) self.assertEqual(p['ul_nr_arfcn'], conf_ncell['dl_nr_arfcn']) # assumes nr_band is TDD
self.assertEqual(p['n_id_cell'], conf_ncell['pci']) self.assertEqual(p['n_id_cell'], conf_ncell['pci'])
self.assertEqual(p['gnb_id_bits'], conf_ncell['gnb_id_bits']) self.assertEqual(p['gnb_id_bits'], conf_ncell['gnb_id_bits'])
self.assertEqual(p['nr_cell_id'], int(conf_ncell['nr_cell_id'], 16)) self.assertEqual(p['nr_cell_id'], int(conf_ncell['nr_cell_id'], 16))
...@@ -352,30 +350,6 @@ class TestCoreNetworkMonitorGadgetUrl(ORSTestCase): ...@@ -352,30 +350,6 @@ class TestCoreNetworkMonitorGadgetUrl(ORSTestCase):
def test_monitor_gadget_url(self): def test_monitor_gadget_url(self):
test_monitor_gadget_url(self) test_monitor_gadget_url(self)
class TestUELTEMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestUENRMonitorGadgetUrl(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps({'testing': True})}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_monitor_gadget_url(self):
test_monitor_gadget_url(self)
class TestSimCard(ORSTestCase): class TestSimCard(ORSTestCase):
@classmethod @classmethod
def requestDefaultInstance(cls, state='started'): def requestDefaultInstance(cls, state='started'):
...@@ -394,62 +368,3 @@ class TestSimCard(ORSTestCase): ...@@ -394,62 +368,3 @@ class TestSimCard(ORSTestCase):
return "core-network" return "core-network"
def test_sim_card(self): def test_sim_card(self):
test_sim_card(self) test_sim_card(self)
class TestUELTEParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-lte"
def test_ue_lte_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_earfcn'], param_dict['dl_earfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], 10)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
class TestUENRParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "ue-nr"
def test_ue_nr_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['cell_groups'][0]['cells'][0]['ssb_nr_arfcn'], param_dict['ssb_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['dl_nr_arfcn'], param_dict['dl_nr_arfcn'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['bandwidth'], '10 MHz')
self.assertEqual(conf['cell_groups'][0]['cells'][0]['band'], param_dict['nr_band'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_dl'], param_dict['n_antenna_dl'])
self.assertEqual(conf['cell_groups'][0]['cells'][0]['n_antenna_ul'], param_dict['n_antenna_ul'])
self.assertEqual(conf['ue_list'][0]['rue_addr'], param_dict['rue_addr'])
self.assertEqual(conf['ue_list'][0]['imsi'], param_dict['imsi'])
self.assertEqual(conf['ue_list'][0]['K'], param_dict['k'])
self.assertEqual(conf['ue_list'][0]['sim_algo'], param_dict['sim_algo'])
self.assertEqual(conf['ue_list'][0]['opc'], param_dict['opc'])
self.assertEqual(conf['ue_list'][0]['amf'], int(param_dict['amf'], 16))
self.assertEqual(conf['ue_list'][0]['sqn'], param_dict['sqn'])
self.assertEqual(conf['ue_list'][0]['impu'], param_dict['impu'])
self.assertEqual(conf['ue_list'][0]['impi'], param_dict['impi'])
self.assertEqual(conf['tx_gain'], param_dict['tx_gain'])
self.assertEqual(conf['rx_gain'], param_dict['rx_gain'])
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "UE Cell. Common properties",
"type": "object",
"required": [
"cell_type",
"cell_kind",
"rf_mode",
"ru"
],
"properties": {
"cell_type": {
"type": "string",
"options": { "hidden": true }
},
"cell_kind": {
"type": "string",
"const": "ue",
"template": "ue",
"options": { "hidden": true }
},
"rf_mode": { "$ref": "../../cell/common.json#/properties/rf_mode" },
"ru": { "$ref": "../../cell/common.json#/$defs/ru-of-cell" }
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "UE Cell",
"type": "object",
"oneOf": [
{ "$ref": "../../ue/cell/lte/input-schema.json" },
{ "$ref": "../../ue/cell/nr/input-schema.json" }
]
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "LTE Cell",
"type": "object",
"required": [
"cell_type",
"cell_kind",
"rf_mode",
"ru",
"dl_earfcn",
"bandwidth"
],
"properties": {
"cell_type": {
"$ref": "../../../ue/cell/common.json#/properties/cell_type",
"const": "lte",
"template": "lte"
},
"cell_kind": { "$ref": "../../../ue/cell/common.json#/properties/cell_kind" },
"rf_mode": { "$ref": "../../../ue/cell/common.json#/properties/rf_mode" },
"ru": { "$ref": "../../../ue/cell/common.json#/properties/ru",
"propertyOrder": 9999"
},
"dl_earfcn": { "$ref": "../../../cell/lte/input-schema.json#/properties/dl_earfcn" },
"ul_earfcn": { "$ref": "../../../cell/lte/input-schema.json#/properties/ul_earfcn" },
"bandwidth": {
"$ref": "../../../cell/common.json#/properties/bandwidth",
"enum": [
1.4,
3,
5,
10,
15,
20
]
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "NR Cell",
"type": "object",
"required": [
"cell_type",
"cell_kind",
"rf_mode",
"ru",
"dl_nr_arfcn",
"bandwidth",
"nr_band"
],
"properties": {
"cell_type": {
"$ref": "../../../ue/cell/common.json#/properties/cell_type",
"const": "nr",
"template": "nr"
},
"cell_kind": { "$ref": "../../../ue/cell/common.json#/properties/cell_kind" },
"rf_mode": { "$ref": "../../../ue/cell/common.json#/properties/rf_mode" },
"ru": { "$ref": "../../../ue/cell/common.json#/properties/ru",
"propertyOrder": 9999"
},
"dl_nr_arfcn": { "$ref": "../../../cell/nr/input-schema.json#/properties/dl_nr_arfcn" },
"bandwidth": { "$ref": "../../../cell/common.json#/properties/bandwidth" },
"nr_band": { "$ref": "../../../cell/nr/input-schema.json#/properties/nr_band" },
"ul_nr_arfcn": { "$ref": "../../../cell/nr/input-schema.json#/properties/ul_nr_arfcn" },
"ssb_nr_arfcn": { "$ref": "../../../cell/nr/input-schema.json#/properties/ssb_nr_arfcn" }
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by UE Cell instantiation (stub)",
"type": "object",
"properties": {}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "UE. Common properties",
"type": "object",
"required": [
"ue_type",
"rue_addr"
],
"properties": {
"$ref": "../sim/input-schema.json#/properties",
"ue_type": {
"type": "string",
"options": { "hidden": true }
},
"rue_addr": {
"title": "[Required] Remote UE address",
"description": "[Required] Address of remote UE server. Default port is 2152.",
"type": "string",
"default": ""
},
"imsi": {
"$ref": "../sim/input-schema.json#/properties/imsi",
"default": "001010123456789"
},
"k": {
"$ref": "../sim/input-schema.json#/properties/k",
"default": "00112233445566778899aabbccddeeff"
},
"sim_algo": {
"$ref": "../sim/input-schema.json#/properties/sim_algo",
"description": "Optional enumeration. xor, milenage or tuak (default = milenage). Set the USIM authentication algorithm. Note: test USIM cards use the XOR algorithm."
},
"opc": {
"$ref": "../sim/input-schema.json#/properties/opc",
"default": "milenage"
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "UE",
"type": "object",
"oneOf": [
{ "$ref": "../ue/lte/input-schema.json" },
{ "$ref": "../ue/nr/input-schema.json" }
]
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "LTE UE",
"type": "object",
"properties": {
"$ref": "../../ue/common.json#/properties",
"ue_type": {
"$ref": "#/properties/ue_type",
"const": "lte",
"template": "lte"
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "NR UE",
"type": "object",
"properties": {
"$ref": "../../ue/common.json#/properties",
"ue_type": {
"$ref": "#/properties/ue_type",
"const": "nr",
"template": "nr"
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by UE instantiation (stub)",
"type": "object",
"properties": {}
}
...@@ -499,6 +499,7 @@ mysqlclient = 2.1.1 ...@@ -499,6 +499,7 @@ mysqlclient = 2.1.1
ptyprocess = 0.6.0 ptyprocess = 0.6.0
paho-mqtt = 1.5.0 paho-mqtt = 1.5.0
pcpp = 1.30 pcpp = 1.30
xmltodict = 0.13.0
# Patched eggs # Patched eggs
PyPDF2 = 1.26.0+SlapOSPatched001 PyPDF2 = 1.26.0+SlapOSPatched001
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