Commit d0a55b7b authored by Kirill Smelkov's avatar Kirill Smelkov

Merge branch 'x/lte-multiru' into xy/lte-multiru

- generic: inactivity_timer moved from global to per-cell
- generic: global disable_sdr removed from schemas - radio enable/disable is controlled by per-RU .txrx_active
- fix publish wrt synthethic RU and cells
- ru/*: fix code not to break under testing=True environment
- fix setting defaults for RU embedded in a cell
- add verification checks wrt incorrect shared instances configuration
- emit big error if both SDR and CPRI RUs are used together
- documentation updates + misc...
parents 81604537 77bba2fa
......@@ -109,8 +109,8 @@ md5sum = b33775a9ab6eae784b6da9f31be48be3
[debian-amd64-bookworm-netinst.iso]
<= debian-amd64-netinst-base
version = 12.1.0
md5sum = 8d77d1b0bcfef29e4d56dc0fbe23de15
version = 12.4.0
md5sum = a03cf771ba9513d908093101a094ac88
alternate-url = https://cdimage.debian.org/cdimage/release/current/${:arch}/iso-cd/${:filename}
[debian-amd64-netinst.iso]
......
......@@ -16,7 +16,7 @@
[template]
filename = instance.cfg
md5sum = a3527093ffc01d8f8fbaf27696ad7b9b
md5sum = 3504aff1982efd60a214e46041483f47
[template-ors]
filename = instance-ors.cfg
......@@ -24,11 +24,19 @@ md5sum = f5c76c3443b75569eb18503dce38e783
[slaplte.jinja2]
_update_hash_filename_ = slaplte.jinja2
md5sum = 55d9182051ce13d07f1bc8e019173ae5
md5sum = 944639e65b9ff3ebe75919bdb5bee6fa
[ru_amarisoft-stats.jinja2.py]
_update_hash_filename_ = ru/amarisoft-stats.jinja2.py
md5sum = 674dcc250c0b6bb43d8546624552fc5d
[ru_amarisoft-rf-info.jinja2.py]
_update_hash_filename_ = ru/amarisoft-rf-info.jinja2.py
md5sum = d2fe2fbe70c6824c514a7c4034a2ddb3
[ru_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/libinstance.jinja2.cfg
md5sum = cf1d71dff3a37a80936ce1c2df373455
md5sum = 39031a3b7f043c905b49986984d49a4b
[ru_sdr_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sdr/libinstance.jinja2.cfg
......@@ -36,20 +44,12 @@ md5sum = b7906ca3a6b17963f78f680fc0842b74
[ru_lopcomm_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/lopcomm/libinstance.jinja2.cfg
md5sum = ec34535512448db3fa40caa00bee3151
md5sum = 667ef223ffbae18f9693fa7d02d6ae88
[ru_sunwave_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sunwave/libinstance.jinja2.cfg
md5sum = bc5d82b8737b6990674b280ef2774be7
[ru_amarisoft-stats.jinja2.py]
_update_hash_filename_ = ru/amarisoft-stats.jinja2.py
md5sum = 674dcc250c0b6bb43d8546624552fc5d
[ru_amarisoft-rf-info.jinja2.py]
_update_hash_filename_ = ru/amarisoft-rf-info.jinja2.py
md5sum = d2fe2fbe70c6824c514a7c4034a2ddb3
[ru_lopcomm_ncclient_common.py]
_update_hash_filename_ = ru/lopcomm/ncclient_common.py
md5sum = 8dbe6a48fc0fca4f0cbd0c746be1aeda
......@@ -80,7 +80,7 @@ md5sum = 2b8b57c5771b2a2203c0e7767e629e55
[ru_xbuildout.py]
_update_hash_filename_ = ru/xbuildout.py
md5sum = 2856e18a18eb8f0af090cfd714e1973a
md5sum = fcc64214e9d497c541f6d4a11fb1afe0
[ru_capdo.c]
_update_hash_filename_ = ru/capdo.c
......@@ -88,11 +88,11 @@ md5sum = 52da9fe3a569199e35ad89ae1a44c30e
[template-enb]
_update_hash_filename_ = instance-enb.jinja2.cfg
md5sum = 4f6ef8c1be0751500fbcc4e5ea24debb
md5sum = 51ce7e6fd96f3c8ad086723722b91c3f
[template-ors-enb]
_update_hash_filename_ = instance-ors-enb.jinja2.cfg
md5sum = fae3b18f36b4196617b8a48251e39726
md5sum = 48dd7b1c51545a78cdd8c3f68e152e8c
[template-core-network]
_update_hash_filename_ = instance-core-network.jinja2.cfg
......@@ -112,7 +112,7 @@ md5sum = dcaac06553a3222b14c0013a13f4a149
[enb.jinja2.cfg]
filename = config/enb.jinja2.cfg
md5sum = cf51fd760ac1d1b5b0bb622bab1bf541
md5sum = 5637fa338ffbc1015b5b6349ede91170
[drb_lte.jinja2.cfg]
filename = config/drb_lte.jinja2.cfg
......@@ -129,7 +129,7 @@ md5sum = 959523597e29b048e45ebf58f7ea4c5b
[mme.jinja2.cfg]
filename = config/mme.jinja2.cfg
md5sum = 44fc9ee5082dd8e0298801f8d4618b06
md5sum = 3d7833ddba3242cedcd74c7db52390c6
[dnsmasq-core-network.jinja2.cfg]
filename = config/dnsmasq-core-network.jinja2.cfg
......
......@@ -53,6 +53,12 @@
"type": "integer",
"default": 204
},
"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
......
......@@ -2,6 +2,7 @@
{%- set B = slaplte.B %}
{%- set J = slaplte.J %}
{%- set jcell_ru_ref = slaplte.jcell_ru_ref %}
{%- set ierror = slaplte.ierror %}
{#- for standalone testing via slapos-render-config.py
NOTE: keep in sync with instance-enb.jinja2.cfg and ru/libinstance.jinja2.cfg #}
......@@ -66,8 +67,8 @@
tac: {{ ncell.tac }},
{#- TODO: consider extending peer/cell/lte with
.allowed_meas_bandwidth and .antenna_port_1 #}
allowed_meas_bandwidth: {{ jlte_n_rb_dl(1.4) }}, // XXX minimum possible bw
antenna_port_1: false, // XXX conservative stub
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",
nr_cell_id: {{ ncell.nr_cell_id }}, // -> {{ B(peercell_ref) }}
......@@ -625,7 +626,7 @@
bitmap: "110011",
cdm_type: "fd_cdm2",
{%- else %}
{%- do error(icell, "unsupported number of DL antennas") %}
{%- do ierror(iru, 'n_antenna_dl=%d is not supported' % ru.n_antenna_dl) %}
{%- endif %}
},
{%- if tdd_config != 3 %}
......
......@@ -2,8 +2,6 @@
log_options: "all.level=error,all.max_size=0,nas.level=debug,nas.max_size=1,s1ap.level=debug,s1ap.max_size=1,ngap.level=debug,ngap.max_size=1,file.rotate=1G,file.path=/dev/null",
log_filename: "{{ directory['log'] }}/mme.log",
com_addr: "127.0.1.2:9000",
{% if slapparameter_dict.get('external_enb_gnb', '') %}
{% if slapparameter_dict.get('use_ipv4', False) %}
gtp_addr: "{{ gtp_addr_v4 }}",
......
......@@ -6,11 +6,9 @@
// Radio Units
rf_driver: {
// XXX vvv <- ru.txrx_active ? XXX how to handle txrx_active for SDR ?
// (tx_gain=-1000 does not work - it still sets tx_gain to min.possible value 14)
name: "sdr",
// RU1 2T1R (sdr)
// RU2 2T1R (sdr)
name: "sdr",
args: "dev0=/dev/sdr1,dev1=/dev/sdr2",
rx_antenna:"tx_rx",
tdd_tx_mod: 1,
......@@ -76,8 +74,8 @@
n_id_cell: 35,
dl_earfcn: 700,
tac: 123,
allowed_meas_bandwidth: 6, // XXX minimum possible bw
antenna_port_1: false, // XXX conservative stub
allowed_meas_bandwidth: 6, // (minimum possible bw)
antenna_port_1: false, // (conservative stub)
},
{
rat: "nr",
......@@ -287,8 +285,8 @@
n_id_cell: 35,
dl_earfcn: 700,
tac: 123,
allowed_meas_bandwidth: 6, // XXX minimum possible bw
antenna_port_1: false, // XXX conservative stub
allowed_meas_bandwidth: 6, // (minimum possible bw)
antenna_port_1: false, // (conservative stub)
},
{
rat: "nr",
......
......@@ -9,16 +9,14 @@
// Radio Units
rf_driver: {
// XXX vvv <- ru.txrx_active ? XXX how to handle txrx_active for SDR ?
// (tx_gain=-1000 does not work - it still sets tx_gain to min.possible value 14)
name: "sdr",
// __UCELL1__ru 2T1R (sdr)
// __UCELL2__ru 2T2R (sdr)
name: "dummy",
args: "dev0=/dev/sdr0,dev1=/dev/sdr2",
rx_antenna:"tx_rx",
tdd_tx_mod: 1,
},
tx_gain: [41, 41, 31, 31],
tx_gain: [-1000, -1000, -1000, -1000],
rx_gain: [42, 32, 32],
......
#!/bin/sh
git diff -C -C $@ -- \
':!config/out' \
':!k/' \
':!buildout.hash.cfg' \
':!test/test.sh' \
':!*.json' \
':!*.json.jinja2' \
':!diff.sh' \
......@@ -151,12 +151,6 @@
"description": "Activates websocket for remote control and sets password",
"type": "string"
},
"inactivity_timer": {
"title": "Inactivity Timer XXX",
"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",
......@@ -169,12 +163,6 @@
"description": "True if GPS should be used for synchronisation",
"type": "boolean"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR XXX kill ?",
"description": "Disables radio",
"type": "boolean"
},
"use_ipv4": {
"default": false,
"title": "Use IPv4",
......
......@@ -3,10 +3,10 @@
{#- defaults for global eNB/gNB parameters.
TODO automatically enb defaults from JSON schema #}
{%- set enb_defaults = {
"com_ws_port": 9001,
"com_addr": '127.0.1.2',
"use_ipv4": False,
"nssai": {'1': {'sst': 1}}
'com_ws_port': 9001,
'com_addr': '127.0.1.2',
'use_ipv4': False,
'nssai': {'1': {'sst': 1}}
} %}
{%- for k,v in enb_defaults|dictsort %}
{%- do slapparameter_dict.setdefault(k, v) %}
......@@ -22,7 +22,6 @@ parts =
{% if slapparameter_dict.get('xlog_fluentbit_forward_host') %}
xlog-fluentbit-service
{% endif %}
check-baseband-latency.py
monitor-base
publish-connection-information
......
......@@ -152,9 +152,7 @@
"$ref": "instance-enb-input-schema.json#/properties/websocket_password"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"$ref": "cell/common.json#/properties/inactivity_timer",
"default": 10000
},
"log_phy_debug": {
......
......@@ -65,7 +65,7 @@
{%- endmacro %}
{%- do ishared_list.append({
'slave_title': iref('RU'),
'slave_reference': 'XXX',
'slave_reference': False,
'_': {
'ru_type': 'sdr',
'ru_link_type': 'sdr',
......@@ -74,7 +74,7 @@
'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',
'txrx_active': 'ACTIVE' if (not slapparameter_dict.disable_sdr) else 'INACTIVE',
} |tojson
})
%}
......@@ -115,7 +115,7 @@
{%- do ishared_list.append({
'slave_title': iref('CELL'),
'slave_reference': 'XXX',
'slave_reference': False,
'_': cell | tojson
})
%}
......@@ -152,7 +152,7 @@
{%- endif %}
{%- do ishared_list.append({
'slave_title': '%s%s' % (iref('PEERCELL'), k),
'slave_reference': 'XXX',
'slave_reference': False,
'_': peercell | tojson
})
%}
......@@ -164,7 +164,7 @@
{%- for k, peer in slapparameter_dict.x2_peers|dictsort %}
{%- do ishared_list.append({
'slave_title': '%s%s' % (iref('X2_PEER'), k),
'slave_reference': 'XXX',
'slave_reference': False,
'_': {
'peer_type': 'nr',
'x2_addr': peer.x2_addr,
......@@ -176,7 +176,7 @@
{%- for k, peer in slapparameter_dict.xn_peers|dictsort %}
{%- do ishared_list.append({
'slave_title': '%s%s' % (iref('XN_PEER'), k),
'slave_reference': 'XXX',
'slave_reference': False,
'_': {
'peer_type': 'nr',
'xn_addr': peer.xn_addr
......
......@@ -27,6 +27,7 @@ extra-context =
depends = $${activate-eggs:recipe}
context =
import xbuildout xbuildout
import netaddr netaddr
import json_module json
import nrarfcn_module nrarfcn
import xearfcn_module xlte.earfcn
......@@ -142,7 +143,6 @@ RootSoftwareInstance = $${:core-network}
url = ${template-enb:target}
filename = instance-enb.cfg
extensions = jinja2.ext.do
# XXX move RU-specific bits from extra context to ru/...
extra-context =
raw monitor_template ${monitor2-template:output}
section comp_id comp-id
......
#!/usr/bin/env -S slapos console
"""request mme/enb and configure radio units and cells"""
"""request mme/enb and configure radio units and cells on Callbox5 + real SlapOS Master"""
# NOTE see krequest-tmru.enb+ for requesting under theia
# XXX workaround for `slapos console` not setting up sys.path the same way as std python does
import sys
......@@ -81,20 +82,6 @@ RU2['mac_addr'] = '90:A9:F7:C0:00:03'
iru1 = iENB(eref('RU1'), RU1)
iru2 = iENB(eref('RU2'), RU2)
# XXX to test wrt buildout code injection
if 0:
RU3 = {
'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(eref('RU3\nzzz ${aaa:bbb}\nccc'), RU3)
# Cells
CELL1 = {
'cell_type': 'lte',
......
#!/usr/bin/env -S slapos console
"""request ors/enb for kirr"""
# XXX deprecated in favour of krequest-cb5.enb+
"""request enb under theia for development"""
# NOTE see krequest-cb5.enb+ for requesting for real
# XXX workaround for `slapos console` not setting up sys.path the same way as std python does
import sys
......@@ -9,22 +9,28 @@ sys.path.insert(0, dirname(__file__))
import kslap
kslap.init(slap)
import json, copy
import os, json, copy
from pprint import pprint
ors = "/srv/slapgrid/slappart35/srv/project/slapos/software/ors-amarisoft/software.cfg"
kamari = "%(HOME)s/srv/project/slapos/software/ors-amarisoft/software.cfg" % os.environ
enb1 = request(ors,
enb1 = kslap.request(kamari,
software_type="enb",
partition_reference="kenb",
filter_kw={"computer_guid": "slaprunner"},
partition_parameter_kw={"_": json.dumps({
'testing': True,
"enb_id": "0x10012",
"gnb_id": "0x54321",
'mme_list': {'1': {'mme_addr': '127.0.0.100'}},
'amf_list': {'1': {'amf_addr': '127.0.0.200'}},
'plmn_list': {'1': {'plmn': '31415'}},
'plmn_list_5g': {'1': {'plmn': '51413', 'tac': 0x4321}},
})})
"""
enb2 = request(ors,
enb2 = kslap.request(kamari,
software_type="enb",
partition_reference="kenb2",
filter_kw={"computer_guid": "slaprunner"},
......@@ -70,6 +76,7 @@ CELL1_a = {
'dl_earfcn': 38050, # 2600 MHz
'pci': 1,
'cell_id': '0x01',
'tac': '0x1234',
'ru': RU1, # RU definition embedded into CELL
}
......@@ -84,6 +91,7 @@ CELL1_b = {
'dl_earfcn': 38100, # 2605 MHz
'pci': 2,
'cell_id': '0x02',
'tac': '0x1234',
'ru': { # CELL1_b shares RU with CELL1_a referring to it via cell
'ru_type': 'ruincell_ref',
'ruincell_ref': 'CELL1_a'
......@@ -129,6 +137,7 @@ kslap.iSHARED(enb1, 'CELL2_a', {
'dl_earfcn': 3350, # 2680 MHz
'pci': 21,
'cell_id': '0x21',
'tac': '0x1234',
'ru': { # CELL2_a links to RU2_a by its reference
'ru_type': 'ru_ref',
'ru_ref': 'RU2_a'
......
......@@ -51,7 +51,7 @@ config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
{%- set J = slaplte.J %}
{%- set jref_of_shared = slaplte.jref_of_shared %}
{%- set jcell_ru_ref = slaplte.jcell_ru_ref %}
{%- set error = slaplte.error %}
{%- set ierror = slaplte.ierror %}
{%- import 'ru_sdr_libinstance.jinja2.cfg' as rudrv_sdr with context %}
{%- import 'ru_lopcomm_libinstance.jinja2.cfg' as rudrv_lopcomm with context %}
{%- import 'ru_sunwave_libinstance.jinja2.cfg' as rudrv_sunwave with context %}
......@@ -61,7 +61,7 @@ config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
{%- set rudrv_init = {} %}
{#- 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
provide several TAP interfaces to instances. See discussion at
......@@ -79,6 +79,7 @@ stop-on-error = true
# StandaloneSlapOS does not provide slaptap
command = :
{%- endif %}
{%- set test_slapnet = netaddr.IPNetwork('1234::/71') %}
{%- if ntap <= 1 %}
[vtap]
......@@ -88,10 +89,16 @@ stop-on-error = false
{%- if ntap == 1 %}
{%- do vtap_list.append(slaplte.tap) %}
[vtap.{{ slaplte.tap }}]
{%- if testing %}
network = {{ str(test_slapnet) }}
gateway = {{ str(test_slapnet[1]) }}
addr = {{ str(test_slapnet[-1]) }}
{%- else %}
network = {{ slap_configuration['tap-ipv6-network'] }}
gateway = {{ slap_configuration['tap-ipv6-gateway'] }}
addr = {{ slap_configuration['tap-ipv6-addr'] }}
{%- endif %}
{%- endif %}
{%- else %}
......@@ -116,7 +123,7 @@ init =
# ( tap subinterface will be created for real later at install time - when it
# is too late to update section options )
if {{ testing }}:
slapnet = netaddr.IPNetwork('1234::/71') # no slaptap on StandaloneSlapOS
slapnet = netaddr.IPNetwork('{{ str(test_slapnet) }}')
else:
slapnet = tapsplit.ifnet6('{{ slaplte.tap }}')
tapnet = tapsplit.netsplit(slapnet, {{ 1+ntap }}) [{{ i }}]
......@@ -228,8 +235,9 @@ config-max-rx-sample-db = {{ slapparameter_dict.get("max_rx_sample_db", 0) }}
{%- endif %}
{{ rudrv.buildout_iru(iru, iru_icell_list) }}
{#- publish information about RU #}
{{ part('publish-%s' % ru_ref) }}
{#- 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) }}
......@@ -241,18 +249,18 @@ cell-list = {{ dumps(iru_icell_ref_list) }}
{%- if ru.ru_link_type == 'cpri' %}
ipv6 = ${vtap.{{ ru.cpri_link._tap }}:gateway}
{%- endif %}
# XXX +error
{%- endif %}
{%- endfor %}
{#- handle configured cells XXX -> cell/libinstance ? #}
{#- 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' %} {# XXX -> instance-enb ? #}
{%- if icell_kind == 'enb' %}
{#- generate CELL-drb.cfg and CELL-sib23.asn #}
{{ part('drb-config-%s' % cell_ref) }}
<= config-base
......@@ -283,13 +291,14 @@ ru_ref = {{ dumps(ru_ref ) }}
ru = {{ dumps(ru ) }}
{%- endif %}
{#- publish information about the cell #}
{{ part('publish-%s' % cell_ref) }}
{#- 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) }}
# XXX +error
{%- endif %}
{%- endfor %}
......
......@@ -5,22 +5,24 @@
{%- set ru = iru['_'] %}
{%- if len(icell_list) != 1 %}
{%- do error(iru, 'ru/lopcomm supports only 1 cell ; requested %d' % len(icell_list)) %}
{%- 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 #}
{%- if not testing %}
{{ promise('%s-netconf-socket' % ru_ref) }}
promise = check_socket_listening
config-host = ${vtap.{{ru.cpri_link._tap}}:gateway}
config-port = 830
{%- endif %}
{#- push firmware to RU #}
[{{ B('%s-software-template' % ru_ref) }}]
{{ part('%s-software-template' % ru_ref) }}
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
_logbase = ${directory:var}/log/{{B('%s-software' % ru_ref)}}
......@@ -45,9 +47,11 @@ mode = 0775
url = {{ ru_lopcomm_software_template }}
output = ${directory:script}/{{B('%s-software.py' % ru_ref)}}
{%- if not testing %}
{{ promise('%s-firmware' % ru_ref) }}
promise = check_command_execute
config-command = [ -f ${ {{-B('%s-software-template' % ru_ref)}}:is_firmware_updated} ]
{%- endif %}
{#- push config to RU #}
......@@ -141,9 +145,11 @@ mode = 0775
hash-files =
${:command-line}
{%- if not testing %}
{{ promise('%s-netconf-connection' % ru_ref) }}
promise = check_command_execute
config-command = [ -f ${ {{-B('%s-stats-template' % ru_ref)}}:is_netconf_connected} ]
{%- endif %}
{{ promise('%s-vswr' % ru_ref) }}
promise = check_lopcomm_vswr
......@@ -230,10 +236,10 @@ hash-files =
{#- amend RU-published information with Lopcomm-specific bits #}
[{{ B('publish-%s' % ru_ref) }}]
firmware = {{ru_lopcomm_firmware_filename}}
[{{ B('ipublish-%s' % ru_ref) }}]
bbu-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}
firmware = {{ru_lopcomm_firmware_filename}}
{%- endmacro %}
......@@ -257,7 +263,7 @@ path_pid = ${directory:run}/sshd.pid
inline =
PidFile ${:path_pid}
Port ${sshd-port:port}
ListenAddress {{my_ipv6}}
ListenAddress ${sshd-port:ip}
Protocol 2
HostKey ${sshd-ssh-host-rsa-key:output}
HostKey ${sshd-ssh-host-ecdsa-key:output}
......
......@@ -47,7 +47,7 @@
#
# Recommended usage of encode in buildout profiles is via B as illustrated below:
#
# {#- B(name) returns buildout-encoded form of name #}
# {#- B(name) escapes name to be safe to use in buildout code. #}
# {%- set B = xbuildout.encode %}
#
# ...
......
......@@ -8,6 +8,13 @@
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:
- B escapes string to be safe to use in buildout code.
- J should be used around macro calls to retrieve returned objects.
- error reports instantiation error.
- ierror reports instantiation error caused by shared instance configuration.
-#}
......@@ -15,7 +22,6 @@
it should be kept in sync with "default" in json schemas
TODO automatically load defaults from JSON schemas #}
{#- XXX add inactivity timer to cell schemas #}
{%- set defaults = {
'ru': {
'txrx_active': 'INACTIVE',
......@@ -79,7 +85,18 @@
%}
{#- XXX explain #}
{#- 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.
......@@ -108,7 +125,7 @@
{%- endmacro %}
{#- jdefault_ssb_nr_arfcn returns default SSB NR ARFCN corresponding to DL NR ARFCN
and subcarrier spacing #}
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) %}
......@@ -127,31 +144,60 @@
{#- bug indicates an error in template logic.
it should not happen. #}
{%- macro bug(msg) %}
{%- do assert(False, msg) %}
{%- do assert(False, 'BUG: %s' % (msg,)) %}
{%- endmacro %}
{#- error reports an error about shared instance #}
{#- XXX -> ierror ? #}
{#- XXX error(ishared, msg) vvv is debug stub -#}
{%- macro error(ishared, msg) %}
{%- set msg = 'E: %s: %s\n' % (J(jref_of_shared(ishared)), msg) %}
{#- error reports instantiation error. #}
{%- macro error(msg) %}
{%- set msg = 'Instantiation Error: %s\n' % msg %}
{%- do assert(False, msg) %}
{%- 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 ---- #}
{#- 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.
-> we extract the reference from slave_title.
#}
{%- macro jref_of_shared(ishared) %}
{#- do print('jref_of_shared %r' % (ishared,)) #}
{%- set ref = ishared['slave_title'] %}
{%- set partition_id = slap_configuration['slap-computer-partition-id'] %}
{%- 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', []) %}
{#- XXX add protection wrt duplicate slave_title -- see jref_of_shared for details #}
{#- 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 %}
{#- check_loaded_everything verifies that all shared instances were handling during the load. #}
{%- macro check_loaded_everything() %}
{%- for ishared in qshared_instance_list %}
{%- do error(ishared, "shared instance of unsupported type") %}
{%- do ierror(ishared, "shared instance of unsupported type") %}
{%- endfor %}
{%- endmacro %}
......@@ -169,8 +215,6 @@
icell_kind=enb - load cells definition to serve them from enb
icell_kind=ue - load cells definition to connect to them
XXX defaults ?
#}
{%- macro load_iru_and_icell(iru_dict, icell_dict, icell_kind) %}
{%- set qother = [] %}
......@@ -179,46 +223,20 @@
{%- set _ = ishared['_'] %}
{%- if 'ru_type' in _ %}
{%- set iru = ishared %}
{%- for k, v in defaults['ru'].items() %}
{%- do _.setdefault(k, v) %}
{%- endfor %}
{%- for k, v in defaults.get('ru/'+_.ru_type, {}).items() %}
{%- do _.setdefault(k, v) %}
{%- endfor %}
{%- if _.ru_link_type == 'cpri' %}
{%- set link = _.cpri_link %}
{%- for k, v in defaults['ru/cpri_link'].items() %}
{%- do link.setdefault(k, v) %}
{%- endfor %}
{%- endif %}
{%- do _ru_set_defaults(_) %}
{%- do iru_dict.update({ref: iru}) %}
{%- elif 'cell_type' in _ and _.get('cell_kind') == icell_kind %}
{%- set icell = ishared %}
{%- if icell_kind == 'enb' %}
{%- for k, v in defaults['cell/%s' % _.cell_type].items() %}
{%- do _.setdefault(k, v) %}
{%- endfor %}
{%- for k, v in defaults['cell/%s/%s' % (_.cell_type, _.rf_mode)].items() %}
{%- do _.setdefault(k, v) %}
{%- endfor %}
{%- endif %}
{%- 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 _.rf_mode == 'tdd' else 15) %} {# XXX just leave at 30 ? #}
{%- do _.setdefault('ssb_nr_arfcn', J(jdefault_ssb_nr_arfcn(_.dl_nr_arfcn, _.nr_band))) %}
{%- else %}
{%- do bug('unreachable') %}
{%- endif %}
{%- do _cell_set_defaults(_, icell_kind) %}
{%- 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 `_<cell_ref>_ru` #}
{#- 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': icell.slave_reference,
'slave_reference': False,
}}) %}
{%- endif %}
{%- else %}
......@@ -231,13 +249,21 @@
{#- 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 #}
{#- XXX also verify that there is no dangling cell -> cell refs in ruincell_ref #}
{%- for _, icell in icell_dict|dictsort %}
{%- set ru_ref = J(jcell_ru_ref(icell, icell_dict)) %}
{%- if ru_ref not in iru_dict %}
{%- do error(icell, "referred RU %s does not exist" % ru_ref) %}
{%- do ierror(icell, "referred RU %r does not exist" % ru_ref) %}
{%- endif %}
{%- endfor %}
......@@ -265,6 +291,42 @@
{%- 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 %}
{%- endif %}
{%- endmacro %}
{%- macro _cell_set_defaults(cell, icell_kind) %}
{%- 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 %}
{%- 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) %}
......@@ -274,16 +336,15 @@
{%- set cell_ref = J(jref_of_shared(icell)) %}
{%- if cell_ref in seen %}
{%- for x in seen %}
{%- do error(x, "%s form a cycle via RU references" % seen) %}
{%- do ierror(x, "%s form a cycle via RU references" % seen) %}
{%- endfor %}
{#- XXX what to return ? #}
{{- 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' %}
{#- XXX first check referred cell exist ? #}
{{- _jcell_ru_ref(icell_dict[ru.ruincell_ref], icell_dict, seen) }}
{%- else %}
{#- ru definition is embedded into cell #}
......@@ -292,24 +353,6 @@
{%- endif %}
{%- endmacro %}
{#- 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.
-> we extract the reference from slave_title.
#}
{%- macro jref_of_shared(ishared) %}
{#- do print('jref_of_shared %r' % (ishared,)) #}
{%- set ref = ishared['slave_title'] %}
{%- set partition_id = slap_configuration['slap-computer-partition-id'] %}
{%- if ref.startswith(partition_id) %}
{%- set ref = ref[len(partition_id):] %}
{%- endif %}
{%- set ref = ref.removeprefix('_') %}
{{- ref | tojson }}
{%- endmacro %}
{#- load_ipeer initializes peer registry.
......@@ -398,23 +441,6 @@
{%- macro ru_config(iru_dict, slapparameter_dict) %}
// Radio Units
rf_driver: {
// XXX vvv <- ru.txrx_active ? XXX how to handle txrx_active for SDR ?
// (tx_gain=-1000 does not work - it still sets tx_gain to min.possible value 14)
{%- if slapparameter_dict.get('disable_sdr', False) %}
name: "dummy",
{%- else %}
name: "sdr",
{%- endif %}
{%- if slapparameter_dict.get('gps_sync', False) %}
sync: "gps",
{%- endif %}
{#- XXX emit big warning if both cpri and sdr are present
to protect users from unclear eNB failures
see https://support.amarisoft.com/issues/26021 for details
XXX below we continue as if sdr and cpri are both supported by enb simultaneously #}
{%- 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 #}
......@@ -435,20 +461,54 @@
{%- else %}
{%- do bug('unreachable') %}
{%- endif %}
{%- do tx_gainv.extend([ru.tx_gain]*ru.n_antenna_dl) %}
{%- 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 '---'}}",
{#- emit sdr-related options if an sdr ru is present #}
{%- if len(ru_sdr_dict) > 0 %}
{%- if do_sdr %}
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 XXX recheck this is ok #}
{%- if len(ru_cpri_dict) > 0 %}
{#- 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) %}
......
......@@ -156,6 +156,7 @@ def iRU2_SDR_tLTE_tNR(ienb):
'n_antenna_ul': 1,
'tx_gain': 51,
'rx_gain': 52,
'txrx_active': 'ACTIVE',
}
RU2 = copy.deepcopy(RU1)
......
......@@ -224,7 +224,7 @@ class RFTestCase4(AmariTestCase):
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': 'INACTIVE'}
ru |= {'tx_gain': 10+i, 'rx_gain': 20+i, 'txrx_active': 'ACTIVE'}
cls.requestShared(imain, 'RU%d' % i, ru)
def CELL(i, ctx):
......@@ -450,6 +450,7 @@ class SDR4:
# 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,
......@@ -482,6 +483,7 @@ class Lopcomm4:
# 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',
......@@ -501,14 +503,14 @@ class Lopcomm4:
'center-of-channel-bandwidth': '%d' % dl_freq,
'channel-bandwidth': '%d' % bw,
'gain': '%d' % tx_gain,
'active': 'INACTIVE',
'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': 'INACTIVE',
'active': 'ACTIVE',
},
}
......@@ -580,6 +582,7 @@ class Sunwave4:
# 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',
......@@ -603,6 +606,7 @@ class RUMultiType4:
# 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',
......
[buildout]
find-links +=
http://www.nexedi.org/static/packages/source/
http://www.nexedi.org/static/packages/source/slapos.buildout/
http://www.nexedi.org/static/packages/source/slapos.buildout/zc.buildout-2.7.1%2Bslapos010.tar.gz
http://www.nexedi.org/static/packages/source/zc.recipe.egg-2.0.3%2Bslapos003.tar.gz
parts =
instance-template
......
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