Commit 30179be5 authored by Kirill Smelkov's avatar Kirill Smelkov

software/ors-amarisoft: ue: Generalize UEsim

Rework UEsim to be able to work with multiple cells, multiple radio units(*),
multiple UE all at the same time. RU, CELLs and UEs are now configured,
simiularly to eNB, via shared instances. Add tests.

Contrary to ORS don't care about backward compatibility here because currently
we have just a few UEsim deployments and migrating them should be easy.

Please see added schemas, tests and updates slapos-render-config on how to use
the new system.

(*) contrary to eNB UEsim does not allow to use one RU for two cells,
parent 4abb4101
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
{%- set icell_dict = {} %} {%- set icell_dict = {} %}
{%- set ipeer_dict = {} %} {%- set ipeer_dict = {} %}
{%- set ipeercell_dict = {} %} {%- set ipeercell_dict = {} %}
{%- do slaplte.load_iru_and_icell(iru_dict, icell_dict) %} {%- do slaplte.load_iru_and_icell(iru_dict, icell_dict, icell_kind='enb') %}
{%- do slaplte.load_ipeer(ipeer_dict) %} {%- do slaplte.load_ipeer(ipeer_dict) %}
{%- do slaplte.load_ipeercell(ipeercell_dict) %} {%- do slaplte.load_ipeercell(ipeercell_dict) %}
{%- do slaplte.check_loaded_everything() %} {%- do slaplte.check_loaded_everything() %}
......
{#- ue_type indicates with which mode ue is instantiated with - lte | nr #} {%- import 'slaplte.jinja2' as slaplte with context %}
{%- set ue_type = slapparameter_dict.ue_type %} {%- set B = slaplte.B %}
{%- do assert(ue_type in ('lte', 'nr'), ue_type) %} {%- 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,70 +23,98 @@ ...@@ -9,70 +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 ue_type == 'lte' %}
{
// LTE cell
multi_ue: true, multi_ue: true,
cells: [ cells: [
{ {%- for cell_ref, icell in icell_dict|dictsort %}
bandwidth: {{ slapparameter_dict.get('bandwidth', '20 MHz') .removesuffix(' MHz') }}, {%- set cell = icell['_'] %}
dl_earfcn: {{ slapparameter_dict.get('dl_earfcn', 0) }}, {%- if cell.cell_type == 'lte' %}
n_antenna_dl: {{ slapparameter_dict.get('n_antenna_dl', 2) }}, {%- set ru_ref = J(jcell_ru_ref(icell)) %}
n_antenna_ul: {{ slapparameter_dict.get('n_antenna_ul', 2) }}, {%- set iru = iru_dict[ru_ref] %}
global_timing_advance: -1, {%- set ru = iru['_'] %}
}
// {{ B(cell_ref) }}
{
rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }},
n_antenna_ul: {{ ru.n_antenna_ul }},
dl_earfcn: {{ cell.dl_earfcn }},
ul_earfcn: {{ cell.ul_earfcn }},
bandwidth: {{ cell.bandwidth }},
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 ue_type == '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', 40) }}, {%- 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', 2) }}, {%- set ru = iru['_'] %}
n_antenna_ul: {{ slapparameter_dict.get('n_antenna_ul', 2) }}, // {{ B(cell_ref) }}
} {
], rf_port: {{ ru._rf_port }},
}, n_antenna_dl: {{ ru.n_antenna_dl }},
{%- endif %} 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 %}
{%- 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 }}",
imsi: "{{ slapparameter_dict.get('imsi', '001010123456789') }}", imsi: "{{ ue.imsi }}",
K: "{{ slapparameter_dict.get('k', '00112233445566778899aabbccddeeff') }}", K: "{{ ue.k }}",
{%- if ue_type == 'lte' %} rue_addr: "{{ ue.rue_addr }}",
ue_category: 12, {%- if ue.ue_type == 'lte' %}
{%- endif %} as_release: 13,
{%- if ue_type == 'nr' %} ue_category: 13,
as_release: 15, {%- elif ue.ue_type == 'nr' %}
ue_category: "nr", as_release: 15,
{%- endif %} ue_category: "nr",
rue_addr: "{{ slapparameter_dict.get('rue_addr', '') }}", {%- else %}
tun_setup_script: "ue-ifup", {%- do bug('unreachable') %}
apn: "internet", {%- endif %}
} tun_setup_script: "ue-ifup",
apn: "internet",
},
{%- endfor %}
], ],
} }
...@@ -33,6 +33,7 @@ eggs-directory = {{ eggs_directory }} ...@@ -33,6 +33,7 @@ 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 ipeer_dict = {} %}
......
...@@ -2,39 +2,5 @@ ...@@ -2,39 +2,5 @@
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {}
"ue": {
"title": "UE",
"oneOf": [
{
"$ref": "ue/lte/input-schema.json"
},
{
"$ref": "ue/nr/input-schema.json"
}
]
},
"tx_gain": {
"title": "Tx gain",
"description": "Tx gain (in dB)",
"type": "number"
},
"rx_gain": {
"title": "Rx gain",
"description": "Rx gain (in dB)",
"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
}
}
} }
# instance-ue implements UEsim service.
[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
...@@ -13,6 +14,15 @@ eggs-directory = {{ eggs_directory }} ...@@ -13,6 +14,15 @@ 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] [myslap]
# see instance-enb.jinja2.cfg about myslap # see instance-enb.jinja2.cfg about myslap
parameter_dict = {{ dumps(slapparameter_dict) }} parameter_dict = {{ dumps(slapparameter_dict) }}
...@@ -88,11 +98,15 @@ environment = ...@@ -88,11 +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 pub_info publish-connection-information section pub_info publish-connection-information
key slap_configuration myslap:configuration key slap_configuration myslap:configuration
key slapparameter_dict myslap:parameter_dict key slapparameter_dict myslap:parameter_dict
import xbuildout xbuildout
${:extra-context}
[lte-ue-config] [lte-ue-config]
<= config-base <= config-base
...@@ -102,6 +116,17 @@ url = ${ue-config-dl:target} ...@@ -102,6 +116,17 @@ 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
...@@ -117,15 +142,3 @@ monitor-title = {{ slapparameter_dict['name'] | string }} ...@@ -117,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
...@@ -207,8 +207,27 @@ extra-context = ...@@ -207,8 +207,27 @@ 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 ru_amarisoft_stats_template ${ru_amarisoft-stats.jinja2.py:target}
raw ru_amarisoft_rf_info_template ${ru_amarisoft-rf-info.jinja2.py:target}
raw ru_lopcomm_stats_template ${ru_lopcomm_stats.jinja2.py:target}
raw ru_lopcomm_config_template ${ru_lopcomm_config.jinja2.py:target}
raw ru_lopcomm_software_template ${ru_lopcomm_software.jinja2.py:target}
raw ru_lopcomm_reset_info_template ${ru_lopcomm_reset-info.jinja2.py:target}
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
url = ${ue_db.jinja2.cfg:target} url = ${ue_db.jinja2.cfg:target}
......
{#- 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 already loaded as
...@@ -16,7 +18,7 @@ ...@@ -16,7 +18,7 @@
#} #}
{%- set iru_dict = {} %} {%- set iru_dict = {} %}
{%- set icell_dict = {} %} {%- set icell_dict = {} %}
{%- do slaplte.load_iru_and_icell(iru_dict, icell_dict) %} {%- do slaplte.load_iru_and_icell(iru_dict, icell_dict, icell_kind) %}
{%- macro buildout() %} {%- macro buildout() %}
...@@ -260,6 +262,7 @@ txrx_active = {{ dumps(ru.txrx_active) }} ...@@ -260,6 +262,7 @@ txrx_active = {{ dumps(ru.txrx_active) }}
{%- set iru = iru_dict[ru_ref] %} {%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %} {%- set ru = iru['_'] %}
{%- if icell_kind == 'enb' %}
{#- generate CELL-drb.cfg and CELL-sib23.asn #} {#- generate CELL-drb.cfg and CELL-sib23.asn #}
{{ part('drb-config-%s' % cell_ref) }} {{ part('drb-config-%s' % cell_ref) }}
<= config-base <= config-base
...@@ -288,6 +291,7 @@ cell_ref = {{ dumps(cell_ref) }} ...@@ -288,6 +291,7 @@ cell_ref = {{ dumps(cell_ref) }}
cell = {{ dumps(cell ) }} cell = {{ dumps(cell ) }}
ru_ref = {{ dumps(ru_ref ) }} ru_ref = {{ dumps(ru_ref ) }}
ru = {{ dumps(ru ) }} ru = {{ dumps(ru ) }}
{%- endif %}
{#- publish information about the cell (skipping synthetic) #} {#- publish information about the cell (skipping synthetic) #}
{%- if icell.slave_reference %} {%- if icell.slave_reference %}
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
- load_iru_and_icell initializes RU and cell registries. - load_iru_and_icell initializes RU and cell registries.
- load_ipeercell initializes peer-cell registry. - load_ipeercell initializes peer-cell registry.
- load_ipeer initializes peer registry. - load_ipeer initializes peer registry.
- load_iue initializes UE registry.
- ru_config emits RF driver configuration for specified Radio Units. - ru_config emits RF driver configuration for specified Radio Units.
In the code iX denotes shared instance of type X, while X denotes In the code iX denotes shared instance of type X, while X denotes
...@@ -73,6 +74,17 @@ ...@@ -73,6 +74,17 @@
'ssb_pos_bitmap': '10000000', 'ssb_pos_bitmap': '10000000',
'tdd_ul_dl_config': '5ms 2UL 7DL 4/6 (default)', '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',
},
} }
%} %}
...@@ -201,8 +213,11 @@ ...@@ -201,8 +213,11 @@
icell_dict keeps cell shared instances: reference -> icell icell_dict keeps cell shared instances: reference -> icell
iru_dict keeps RU shared instances + RU whose definition is embedded into a cell: reference -> iRU iru_dict keeps RU shared instances + RU whose definition is embedded into a cell: reference -> iRU
in the kept instances _ is automatically json-decoded 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) %} {%- macro load_iru_and_icell(iru_dict, icell_dict, icell_kind) %}
{%- set qother = [] %} {%- set qother = [] %}
{%- for ishared in qshared_instance_list %} {%- for ishared in qshared_instance_list %}
{%- set ref = J(jref_of_shared(ishared)) %} {%- set ref = J(jref_of_shared(ishared)) %}
...@@ -211,9 +226,9 @@ ...@@ -211,9 +226,9 @@
{%- set iru = ishared %} {%- set iru = ishared %}
{%- do _ru_set_defaults(_) %} {%- do _ru_set_defaults(_) %}
{%- do iru_dict.update({ref: iru}) %} {%- do iru_dict.update({ref: iru}) %}
{%- elif 'cell_type' in _ and _.get('cell_kind') == 'enb' %} {%- elif 'cell_type' in _ and _.get('cell_kind') == icell_kind %}
{%- set icell = ishared %} {%- set icell = ishared %}
{%- do _cell_set_defaults(_, icell_dict) %} {%- do _cell_set_defaults(_, icell_kind, icell_dict) %}
{%- do icell_dict.update({ref: icell}) %} {%- do icell_dict.update({ref: icell}) %}
{%- set ru = _['ru'] %} {%- set ru = _['ru'] %}
{%- if ru.ru_type not in ('ru_ref', 'ruincell_ref') %} {%- if ru.ru_type not in ('ru_ref', 'ruincell_ref') %}
...@@ -294,15 +309,17 @@ ...@@ -294,15 +309,17 @@
{%- endif %} {%- endif %}
{%- endmacro %} {%- endmacro %}
{%- macro _cell_set_defaults(cell, icell_dict) %} {%- macro _cell_set_defaults(cell, icell_kind, icell_dict) %}
{%- for k, v in defaults['cell/%s' % cell.cell_type].items() %} {%- if icell_kind == 'enb' %}
{%- do cell.setdefault(k, v) %} {%- for k, v in defaults['cell/%s' % cell.cell_type].items() %}
{%- endfor %} {%- do cell.setdefault(k, v) %}
{%- for k, v in defaults['cell/%s/%s' % (cell.cell_type, cell.rf_mode)].items() %} {%- endfor %}
{%- do cell.setdefault(k, v) %} {%- for k, v in defaults['cell/%s/%s' % (cell.cell_type, cell.rf_mode)].items() %}
{%- endfor %} {%- do cell.setdefault(k, v) %}
{%- set n = len(list(icell_dict|dictsort | selectattr('1._.cell_type', '==', cell.cell_type))) %} {%- endfor %}
{%- do cell.setdefault('root_sequence_index', 1 + 203*(cell.cell_type == 'lte') + n) %} {%- 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' %} {%- if cell.cell_type == 'lte' %}
{%- do cell.setdefault('ul_earfcn', J(jdefault_ul_earfcn(cell.dl_earfcn))) %} {%- do cell.setdefault('ul_earfcn', J(jdefault_ul_earfcn(cell.dl_earfcn))) %}
{%- elif cell.cell_type == 'nr' %} {%- elif cell.cell_type == 'nr' %}
...@@ -396,6 +413,30 @@ ...@@ -396,6 +413,30 @@
{%- endmacro %} {%- 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 ---- #} {#- ---- building configuration ---- #}
{#- ru_config emits RF driver configuration for specified Radio Units. #} {#- ru_config emits RF driver configuration for specified Radio Units. #}
......
...@@ -560,27 +560,71 @@ def _do_enb_with(iru_icell_func): ...@@ -560,27 +560,71 @@ def _do_enb_with(iru_icell_func):
# ---- UE ---- # ---- UE ----
def do_ue(): def do_ue():
def do(src, out, slapparameter_dict): iue = Instance('ue')
jslapparameter_dict = json.dumps(slapparameter_dict) iue.ishared('UCELL1', {
json_params = """{ 'cell_type': 'lte',
"slap_configuration": { 'cell_kind': 'ue',
"tap-name": "slaptap9" 'rf_mode': 'tdd',
}, 'bandwidth': 5,
"directory": { 'dl_earfcn': 38050, # 2600 MHz
"log": "log", 'ru': {
"etc": "etc", 'ru_type': 'sdr',
"var": "var" 'ru_link_type': 'sdr',
}, 'sdr_dev_list': [0],
"pub_info": { 'n_antenna_dl': 2,
"rue_bind_addr": "::1", 'n_antenna_ul': 1,
"com_addr": "[::1]:9002" 'tx_gain': 41,
}, 'rx_gain': 42,
"slapparameter_dict": %(jslapparameter_dict)s }
}""" })
j2render(src, out, json_params % locals()) iue.ishared('UCELL2', {
'cell_type': 'nr',
do('ue.jinja2.cfg', 'ue-lte.cfg', {'ue_type': 'lte', 'rue_addr': 'host1'}) 'cell_kind': 'ue',
do('ue.jinja2.cfg', 'ue-nr.cfg', {'ue_type': 'nr', 'rue_addr': 'host2'}) '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():
......
...@@ -65,12 +65,39 @@ ...@@ -65,12 +65,39 @@
"index": 7 "index": 7
}, },
"ue": { "ue": {
"title": "UE", "title": "UEsim",
"description": "UE Configuration", "description": "UEsim Configuration",
"software-type": "ue", "software-type": "ue",
"request": "instance-ue-input-schema.json", "request": "instance-ue-input-schema.json",
"response": "instance-ue-schema.json", "response": "instance-ue-schema.json",
"index": 8 "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
} }
} }
} }
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
# Here we test: # Here we test:
# #
# - enb (see TestENB_*) # - enb (see TestENB_*)
# - uesim (see TestUEsim_*)
# #
# Currently there is no tests for core-network, because for core-network # 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 # there is no difference in between generic and ORS modes and core-network is
...@@ -57,6 +58,7 @@ setUpModule, _AmariTestCase = makeModuleSetUpAndTestCaseClass( ...@@ -57,6 +58,7 @@ setUpModule, _AmariTestCase = makeModuleSetUpAndTestCaseClass(
# - LTE/NR indicate LTE/NR cell with given downlink frequency. # - LTE/NR indicate LTE/NR cell with given downlink frequency.
# - BW indicates specified bandwidth. # - BW indicates specified bandwidth.
# - CENB indicates a ENB-kind cell. # - CENB indicates a ENB-kind cell.
# - CUE indicates an UE-kind cell.
# - TAC indicates specified Tracking Area Code. # - TAC indicates specified Tracking Area Code.
# - LTE_PEER/NR_PEER indicate an LTE/NR ENB-PEER-kind cell. # - LTE_PEER/NR_PEER indicate an LTE/NR ENB-PEER-kind cell.
# - X2_PEER/XN_PEER indicate an LTE/NR ENB peer. # - X2_PEER/XN_PEER indicate an LTE/NR ENB peer.
...@@ -92,6 +94,9 @@ def CENB(cell_id, pci): ...@@ -92,6 +94,9 @@ def CENB(cell_id, pci):
'pci': pci, 'pci': pci,
} }
# CUE indicates an UE-kind cell.
CUE = {'cell_kind': 'ue'}
# TAC returns basic parameters to indicate specified Tracking Area Code. # TAC returns basic parameters to indicate specified Tracking Area Code.
def TAC(tac): def TAC(tac):
return { return {
...@@ -659,6 +664,125 @@ class TestENB_Sunwave4 (ENBTestCase4, Sunwave4): pass ...@@ -659,6 +664,125 @@ class TestENB_Sunwave4 (ENBTestCase4, Sunwave4): pass
class TestENB_RUMultiType4(ENBTestCase4, RUMultiType4): 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 ----
# yamlpp_load loads yaml config file after preprocessing it. # yamlpp_load loads yaml config file after preprocessing it.
...@@ -762,7 +886,7 @@ class TestAssertMatch(unittest.TestCase): ...@@ -762,7 +886,7 @@ class TestAssertMatch(unittest.TestCase):
# run only on leaf test classes. # run only on leaf test classes.
def __dir__(): def __dir__():
d = list(sorted(globals().keys())) d = list(sorted(globals().keys()))
abstract = {'AmariTestCase', 'RFTestCase4', 'ENBTestCase4'} abstract = {'AmariTestCase', 'RFTestCase4', 'ENBTestCase4', 'UEsimTestCase4'}
for _ in abstract: for _ in abstract:
d.remove(_) d.remove(_)
return d return d
{
"$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",
"type": "object",
"oneOf": [
{ "$ref": "../ue/lte/input-schema.json" },
{ "$ref": "../ue/nr/input-schema.json" }
]
}
...@@ -11,26 +11,6 @@ ...@@ -11,26 +11,6 @@
"$ref": "#/properties/ue_type", "$ref": "#/properties/ue_type",
"const": "lte", "const": "lte",
"template": "lte" "template": "lte"
},
"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"
} }
} }
} }
...@@ -9,30 +9,8 @@ ...@@ -9,30 +9,8 @@
"ue_type": { "ue_type": {
"$ref": "#/properties/ue_type", "$ref": "#/properties/ue_type",
"const": "lte", "const": "nr",
"template": "lte" "template": "nr"
},
"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"
} }
} }
} }
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by UE instantiation (stub)",
"type": "object",
"properties": {}
}
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