Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
slapos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
105
Merge Requests
105
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
nexedi
slapos
Commits
1685efc2
Commit
1685efc2
authored
Dec 12, 2024
by
Joanne Hugé
Browse files
Options
Browse Files
Download
Plain Diff
Update Release Candidate
parents
be97c578
3ec53860
Changes
28
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
1754 additions
and
725 deletions
+1754
-725
software/simpleran/README.md
software/simpleran/README.md
+4
-4
software/simpleran/buildout.hash.cfg
software/simpleran/buildout.hash.cfg
+15
-15
software/simpleran/changelog.rst
software/simpleran/changelog.rst
+15
-0
software/simpleran/config/enb.jinja2.cfg
software/simpleran/config/enb.jinja2.cfg
+255
-352
software/simpleran/config/ims.jinja2.cfg
software/simpleran/config/ims.jinja2.cfg
+2
-2
software/simpleran/config/mme.jinja2.cfg
software/simpleran/config/mme.jinja2.cfg
+9
-10
software/simpleran/config/ue.jinja2.cfg
software/simpleran/config/ue.jinja2.cfg
+5
-1
software/simpleran/instance-core-network-input-schema.json
software/simpleran/instance-core-network-input-schema.json
+38
-4
software/simpleran/instance-core-network.jinja2.cfg
software/simpleran/instance-core-network.jinja2.cfg
+53
-45
software/simpleran/instance-enb-input-schema.json
software/simpleran/instance-enb-input-schema.json
+435
-0
software/simpleran/instance-enb.jinja2.cfg
software/simpleran/instance-enb.jinja2.cfg
+62
-16
software/simpleran/instance-ors-enb-input-schema.json
software/simpleran/instance-ors-enb-input-schema.json
+240
-26
software/simpleran/instance-ors-enb.jinja2.cfg
software/simpleran/instance-ors-enb.jinja2.cfg
+42
-40
software/simpleran/instance-ors-gnb-input-schema.json
software/simpleran/instance-ors-gnb-input-schema.json
+240
-35
software/simpleran/instance-ors-ue.jinja2.cfg
software/simpleran/instance-ors-ue.jinja2.cfg
+2
-1
software/simpleran/instance-ors.cfg
software/simpleran/instance-ors.cfg
+9
-8
software/simpleran/instance-ue.jinja2.cfg
software/simpleran/instance-ue.jinja2.cfg
+17
-12
software/simpleran/instance.cfg
software/simpleran/instance.cfg
+102
-32
software/simpleran/peer/cell/common.json
software/simpleran/peer/cell/common.json
+2
-1
software/simpleran/peer/cell/lte/input-schema.json
software/simpleran/peer/cell/lte/input-schema.json
+10
-1
software/simpleran/peer/cell/nr/input-schema.json
software/simpleran/peer/cell/nr/input-schema.json
+10
-1
software/simpleran/ru/amarisoft-rf-info.jinja2.py
software/simpleran/ru/amarisoft-rf-info.jinja2.py
+20
-16
software/simpleran/ru/amarisoft-stats.jinja2.py
software/simpleran/ru/amarisoft-stats.jinja2.py
+7
-20
software/simpleran/ru/libinstance.jinja2.cfg
software/simpleran/ru/libinstance.jinja2.cfg
+14
-8
software/simpleran/slaplte.jinja2
software/simpleran/slaplte.jinja2
+1
-0
software/simpleran/software.cfg
software/simpleran/software.cfg
+27
-0
software/simpleran/test/test.py
software/simpleran/test/test.py
+10
-6
software/simpleran/test/test_ors.py
software/simpleran/test/test_ors.py
+108
-69
No files found.
software/simpleran/README.md
View file @
1685efc2
...
...
@@ -49,16 +49,16 @@ Simpleran SR needs:
| /opt/amarisoft/v20XX-XX-XX.X | Binaries | |
| /opt/amarisoft/.amarisoft | Licenses | |
| /opt/amarisoft/init-sdr | Init SDR driver | |
| /opt/amarisoft/get-sdr-info | Get SDR info | |
| /opt/amarisoft/get-license-info | Get license info | |
| /opt/amarisoft/get-amarisoft-info | Get amarisoft info | |
| /opt/amarisoft/rm-tmp-lte | Remove files in /tmp | Configure amarisoft to disable this lock |
| /opt/amarisoft/init-enb | Set performance governor | Do it in playbook |
| /opt/amarisoft/init-ue | | Do it in playbook |
| /opt/amarisoft/init-mme | | Do it in playbook |
| /opt/amarisoft/format-ims | Format IMS slaptun | Do it in slapformat |
| /opt/sdr/get-sdr-info | Get SDR info | |
| /opt/simpleran/format-ims | Format IMS slaptun | Do it in slapformat |
Playbook needs:
| Path | Use | How to remove (if possible ) |
|------------------------------------|--------------------------|------------------------------------------|
| /opt/amarisoft/get-
license-info | Get license info
| |
| /opt/amarisoft/get-
amarisoft-info | Get amarisoft info
| |
software/simpleran/buildout.hash.cfg
View file @
1685efc2
...
...
@@ -16,27 +16,27 @@
[template]
filename = instance.cfg
md5sum =
bb6cb40fe200d03435c5c5eae27af958
md5sum =
9013df1ac77d35a1fc8df37bb5615dcd
[template-ors]
filename = instance-ors.cfg
md5sum =
8c2abee8eb0a538ad8ae1a84e140af69
md5sum =
307e38207945a9adcfea0263cba9d3a6
[slaplte.jinja2]
_update_hash_filename_ = slaplte.jinja2
md5sum = 8
d6eb90fc1191c3a1b24200df2ebf4fa
md5sum = 8
0f86d108ce8634f9577356ce074a560
[ru_amarisoft-stats.jinja2.py]
_update_hash_filename_ = ru/amarisoft-stats.jinja2.py
md5sum =
31b609f80a82b6efed963161c8907878
md5sum =
b492c3a520d48b9c45ea583eec435109
[ru_amarisoft-rf-info.jinja2.py]
_update_hash_filename_ = ru/amarisoft-rf-info.jinja2.py
md5sum =
93a5e07a763b619747255b4e03b50bbe
md5sum =
3b6c08d7685e7c93ab451bec25e4815f
[ru_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/libinstance.jinja2.cfg
md5sum =
f0d7d38ef486f5be44020c3d5ce2a94f
md5sum =
349b02e6993409361176a865b780b871
[ru_sdr_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sdr/libinstance.jinja2.cfg
...
...
@@ -60,23 +60,23 @@ md5sum = 52da9fe3a569199e35ad89ae1a44c30e
[template-enb]
_update_hash_filename_ = instance-enb.jinja2.cfg
md5sum =
b116b58365600f12129d458750b57c71
md5sum =
04b723fc2a3d5555243921823b0e087b
[template-ors-enb]
_update_hash_filename_ = instance-ors-enb.jinja2.cfg
md5sum =
585457493ce5302ba1f1073b8a3b877
c
md5sum =
bdc8ca95cad8374f24af7ab6a276b61
c
[template-ors-ue]
_update_hash_filename_ = instance-ors-ue.jinja2.cfg
md5sum =
f4389a92fb111447e7976e452db78607
md5sum =
82449c34a4632191931ce8aa88ce72e6
[template-core-network]
_update_hash_filename_ = instance-core-network.jinja2.cfg
md5sum =
dab992c02a363e00cdc86f102a7ae489
md5sum =
92fd8377819ae6e844f77937cecfa605
[template-ue]
_update_hash_filename_ = instance-ue.jinja2.cfg
md5sum =
0c387a13a57f7270595b74e11be8eb36
md5sum =
763fa11181527bf4c481fd2e6a2f7c59
[template-obsolete]
_update_hash_filename_ = instance-obsolete.jinja2.cfg
...
...
@@ -88,7 +88,7 @@ md5sum = dd50b4e4780830ddbde28b84af118f18
[enb.jinja2.cfg]
filename = config/enb.jinja2.cfg
md5sum =
573cb004c21aa5f9ad8baf7b4dbbeb43
md5sum =
d19d631a0181a5449be8859274d4fade
[drb_lte.jinja2.cfg]
filename = config/drb_lte.jinja2.cfg
...
...
@@ -108,7 +108,7 @@ md5sum = 9dbd93036c15c87c6de74b88b34062b6
[mme.jinja2.cfg]
filename = config/mme.jinja2.cfg
md5sum =
b86f0e7a0d890771d56aee22838d6487
md5sum =
eff3bd1b191cfab251a602ad99a8316e
[dnsmasq-core-network.jinja2.cfg]
filename = config/dnsmasq-core-network.jinja2.cfg
...
...
@@ -120,11 +120,11 @@ md5sum = 95f4f8fb85e0480eb3e9059b9db26540
[ims.jinja2.cfg]
filename = config/ims.jinja2.cfg
md5sum =
f07c85916bcb7e4002c8edc3d087c1be
md5sum =
8379c4edcccc03db94acceca77e3cd07
[ue.jinja2.cfg]
filename = config/ue.jinja2.cfg
md5sum =
1c65b7227d1416a636a3f04fcabddcdf
md5sum =
9b095aed884849a712366e6c2e5953c7
[software.cfg.html]
_update_hash_filename_ = gadget/software.cfg.html
...
...
software/simpleran/changelog.rst
View file @
1685efc2
Changelog
=========
Version 1.0.383 (2024-12-11)
-------------
* Amarisoft version is now required to be 2024-11-21 for this version of the software release
* Support handover between 4G and 5G
* Generate unique values on ORS for the following parameters:
- eNB ID
- gNB ID
- Cell ID
- Physical Cell ID
- Root Sequence Index
* Add PDN list parameter in core-network
* Allow to configure multiple iperf3 servers
* Publish MAC address
Version 1.0.379 (2024-10-09)
-------------
...
...
software/simpleran/config/enb.jinja2.cfg
View file @
1685efc2
This diff is collapsed.
Click to expand it.
software/simpleran/config/ims.jinja2.cfg
View file @
1685efc2
...
...
@@ -22,11 +22,11 @@
],
mms_server_bind_addr: "{{ internet_ipv4 }}:1111",
sctp_addr: "{{ slap
_configuration['configuration.ims_addr']
}}",
sctp_addr: "{{ slap
parameter_dict.ims_addr
}}",
cx_server_addr: "127.0.1.100",
cx_bind_addr: "{{ slap
_configuration['configuration.ims_addr']
}}",
cx_bind_addr: "{{ slap
parameter_dict.ims_addr
}}",
rx_server_addr: "127.0.1.100",
...
...
software/simpleran/config/mme.jinja2.cfg
View file @
1685efc2
...
...
@@ -30,7 +30,7 @@
gtp_addr: "{{ gtp_addr_v6 }}",
{%- endif %}
{%- else %}
gtp_addr: "{{ slap
_configuration['configuration.gtp_addr']
}}",
gtp_addr: "{{ slap
parameter_dict.gtp_addr
}}",
{%- endif %}
plmn: "{{ slapparameter_dict.get('core_network_plmn', "00101") }}",
...
...
@@ -68,18 +68,20 @@
fifteen_bearers: false,
{%- if support_ims == 'True' %}
ims_list: [
{
ims_addr: "{{ slap
_configuration['configuration.ims_addr']
}}",
bind_addr: "{{ slap
_configuration['configuration.ims_bind']
}}",
ims_addr: "{{ slap
parameter_dict.ims_addr
}}",
bind_addr: "{{ slap
parameter_dict.ims_bind
}}",
}
],
{%- endif %}
pdn_list: [
{
access_point_name: ["default", "internet", "sos"],
access_point_name: [
{%- for _, pdn in slapparameter_dict.pdn_list |dictsort -%}
"{{ pdn.name }}",
{%- endfor -%}
],
pdn_type: "ipv4v6",
tun_ifname: "{{ tun_name }}",
first_ip_addr: "{{ internet_ipv4_start }}",
...
...
@@ -91,17 +93,15 @@
{%- else %}
dns_addr: ["8.8.8.8", "2001:4860:4860::8888"],
{%- endif %}
erabs: [
{
qci:
9
,
qci:
{{ slapparameter_dict.qci }}
,
priority_level: 15,
pre_emption_capability: "shall_not_trigger_pre_emption",
pre_emption_vulnerability: "not_pre_emptable",
},
],
},
{%- if support_ims == 'True' %}
{
access_point_name: "ims",
pdn_type: "ipv4v6",
...
...
@@ -126,7 +126,6 @@
},
],
},
{%- endif %}
],
tun_setup_script: "{{ ifup_empty }}",
...
...
software/simpleran/config/ue.jinja2.cfg
View file @
1685efc2
...
...
@@ -22,7 +22,11 @@
{%- if not ors %}
rue_bind_addr: "{{ pub_info['rue_bind_addr'] }}",
com_addr: "[[ ",
com_addr: "{{ slapparameter_dict.com_addr }}:{{ slapparameter_dict.com_ws_port }}",
com_auth: {
password: "{{ websocket_password }}",
unsecure: false,
},
{%- endif %}
{# instantiate radio units #}
...
...
software/simpleran/instance-core-network-input-schema.json
View file @
1685efc2
...
...
@@ -16,10 +16,10 @@
"type"
:
"boolean"
},
"iperf3"
:
{
"default"
:
false
,
"title"
:
"iperf3 UDP server"
,
"description"
:
"Activate iperf3 UDP server"
,
"type"
:
"
boolean
"
"default"
:
0
,
"title"
:
"iperf3 UDP server
count
"
,
"description"
:
"Activate
one or multiple
iperf3 UDP server"
,
"type"
:
"
number
"
},
"local_domain"
:
{
"default"
:
""
,
...
...
@@ -51,6 +51,40 @@
"description"
:
"Set to true to force a static IPv4 for each UE. If true, the number of UE is limited."
,
"type"
:
"boolean"
},
"pdn_list"
:
{
"title"
:
"PDN list"
,
"description"
:
"Configure the available EPS Packet Data Networks and 5GS Data Network Names."
,
"default"
:
{
"internet"
:
{
"name"
:
"internet"
},
"default"
:
{
"name"
:
"default"
},
"sos"
:
{
"name"
:
"sos"
}
},
"patternProperties"
:
{
".*"
:
{
"properties"
:
{
"name"
:
{
"title"
:
"APN name"
,
"description"
:
"APN name"
,
"type"
:
"string"
}
},
"type"
:
"object"
}
},
"type"
:
"object"
},
"qci"
:
{
"default"
:
9
,
"title"
:
"QCI of default E-RAB"
,
"description"
:
"QoS Class Identifier of the default E-RAB"
,
"type"
:
"number"
},
"eps_5gs_interworking"
:
{
"title"
:
"EPS 5GS Interworking"
,
"type"
:
"string"
,
...
...
software/simpleran/instance-core-network.jinja2.cfg
View file @
1685efc2
{%- if lte_version|replace("-", "")|int < 20240502 %}
{%- set support_ims = false %}
{%- else %}
{%- set support_ims = true %}
{%- endif %}
{#- defaults for global core network parameters.
TODO automatically load enb defaults from JSON schema #}
{%- set mme_defaults = {
'gtp_addr': '127.0.1.100',
'ims_addr': '127.0.0.1',
'ims_bind': '127.0.0.2',
'qci': 9,
'pdn_list': {
'internet': {'name': 'internet'},
'default': {'name': 'default'},
'sos': {'name': 'sos'}
}
} %}
{%- for k,v in mme_defaults|dictsort %}
{%- do slapparameter_dict.setdefault(k, v) %}
{%- endfor %}
{%- set dns_slave_instance_list = [] %}
{%- set sim_slave_instance_list = [] %}
{%- set fixed_ip = slapparameter_dict.get("fixed_ips", False) %}
...
...
@@ -78,16 +88,14 @@ parts =
mme-service
ims-config
mt-call-config
{%- if support_ims %}
ims-service
{%- endif %}
monitor-base
check-interface-up.py
publish-connection-information
{%
if slapparameter_dict.get("iperf3", None
) %}
iperf-service
iperf-listen-promise
{%
endif
%}
{%
- for i in range(slapparameter_dict.get("iperf3", 0)
) %}
iperf-service
-{{ i }}
iperf-
{{ i }}-
listen-promise
{%
- endfor
%}
{% if slapparameter_dict.get("local_domain", '') %}
dnsmasq-service
{% endif %}
...
...
@@ -101,6 +109,12 @@ eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true
[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) }}
[slap-configuration]
recipe = slapos.cookbook:slapconfiguration.serialised
computer = {{ slap_connection['computer-id'] }}
...
...
@@ -108,9 +122,6 @@ partition = {{ slap_connection['partition-id'] }}
url = {{ slap_connection['server-url'] }}
key = {{ slap_connection['key-file'] }}
cert = {{ slap_connection['cert-file'] }}
configuration.gtp_addr = 127.0.1.100
configuration.ims_addr = 127.0.0.1
configuration.ims_bind = 127.0.0.2
ue_db_path = ${ue-db-config:output}
{%- if fixed_ip %}
sim_list = ${sim-ip-configuration:sim-with-ip-list}
...
...
@@ -152,12 +163,10 @@ output = ${directory:bin}/${:_buildout_section_name_}
ims-log = ${directory:log}/ims-output.log
inline =
#!/bin/sh
{% if not slapparameter_dict.get("testing", False) %}
(echo && echo && date "+[%Y/%m/%d %T.%N %Z] Starting IMS software..." && echo) >> ${:ims-log};
tail -c 1M ${:ims-log} > ${:ims-log}.tmp;
mv ${:ims-log}.tmp ${:ims-log};
{{ ims }}/lteims ${directory:etc}/ims.cfg >> ${:ims-log} 2>> ${:ims-log};
{% endif %}
{{ amarisoft['ims_dir'] }}/lteims ${directory:etc}/ims.cfg >> ${:ims-log} 2>> ${:ims-log};
### IMS
[ims-service]
...
...
@@ -173,7 +182,7 @@ hash-files =
${ims-sh-wrapper:output}
environment =
LD_LIBRARY_PATH={{ openssl_location }}/lib:{{ nghttp2_location }}/lib
AMARISOFT_PATH=
/opt/amarisoft/.amarisoft
AMARISOFT_PATH=
{{ amarisoft['license_dir'] }}
[mme-sh-wrapper]
recipe = slapos.recipe.template
...
...
@@ -181,14 +190,12 @@ output = ${directory:bin}/${:_buildout_section_name_}
mme-log = ${directory:log}/mme-output.log
inline =
#!/bin/sh
{% if not slapparameter_dict.get("testing", False) %}
sudo -n /opt/amarisoft/init-mme;
sudo -n {{ amarisoft['dir'] }}/init-mme;
rm -f ${directory:var}/lte_ue.db;
(echo && echo && date "+[%Y/%m/%d %T.%N %Z] Starting MME software..." && echo) >> ${:mme-log};
tail -c 1M ${:mme-log} > ${:mme-log}.tmp;
mv ${:mme-log}.tmp ${:mme-log};
{{ mme }}/ltemme ${directory:etc}/mme.cfg >> ${:mme-log} 2>> ${:mme-log};
{% endif %}
{{ amarisoft['mme_dir'] }}/ltemme ${directory:etc}/mme.cfg >> ${:mme-log} 2>> ${:mme-log};
### MME
[mme-service]
...
...
@@ -205,7 +212,7 @@ hash-files =
${mme-sh-wrapper:output}
environment =
LD_LIBRARY_PATH={{ openssl_location }}/lib:{{ nghttp2_location }}/lib
AMARISOFT_PATH=
/opt/amarisoft/.amarisoft
AMARISOFT_PATH=
{{ amarisoft['license_dir'] }}
### EMPTY mme-ifup script
[mme-ifup-empty]
...
...
@@ -214,24 +221,23 @@ wrapper-path = ${directory:bin}/mme-ifup-empty
command-line = echo Using interface
mode = 775
{% if slapparameter_dict.get("iperf3", None) %}
### iperf3
[iperf-service]
{%- for i in range(slapparameter_dict.get("iperf3", 0)) %}
[iperf-service-{{ i }}]
recipe = slapos.cookbook:wrapper
port =
5001
port =
{{ 5001 + i }}
ip = ${slap-configuration:tun-ipv4-addr}
command-line = {{ iperf3_location }}/bin/iperf3 --server --interval 1 --port ${:port} --bind ${:ip}
wrapper-path = ${directory:service}/iperf3
wrapper-path = ${directory:service}/iperf3
-{{ i }}
mode = 0775
pidfile = ${directory:run}/iperf3.pid
pidfile = ${directory:run}/iperf3
-{{ i }}
.pid
[iperf-listen-promise]
[iperf-
{{ i }}-
listen-promise]
<= monitor-promise-base
promise = check_socket_listening
name = iperf
3
-port-listening.py
config-host = ${iperf-service:ip}
config-port = ${iperf-service:port}
{% end
if
%}
name = iperf
-{{ i }}
-port-listening.py
config-host = ${iperf-service
-{{ i }}
:ip}
config-port = ${iperf-service
-{{ i }}
:port}
{% end
for
%}
[config-base]
recipe = slapos.recipe.template:jinja2
...
...
@@ -240,7 +246,7 @@ extra-context =
context =
section directory directory
section slap_configuration slap-configuration
key slapparameter_dict
slap-configuration:configuration
key slapparameter_dict
myslap:parameter_dict
raw gtp_addr_v6 {{ my_ipv6 }}
raw gtp_addr_v4 {{ lan_ipv4 }}
import netaddr netaddr
...
...
@@ -269,8 +275,6 @@ context =
<= config-base
url = {{ mme_template }}
output = ${directory:etc}/mme.cfg
extra-context =
raw support_ims {{ support_ims }}
{% if slapparameter_dict.get("local_domain", '') %}
[dnsmasq-config]
...
...
@@ -321,15 +325,19 @@ password = {{ slapparameter_dict['monitor-password'] | string }}
[publish-connection-information]
<= monitor-publish
recipe = slapos.cookbook:publish.serialised
{%- if support_ims %}
ims = Enabled
{%- else %}
ims = Unsupported (Amarisoft version >= 2024-05-02 is required), 5G may not work with your UE
{%- endif %}
core-network-ipv6 = {{ my_ipv6 }}
core-network-ipv4 = {{ lan_ipv4 }}
amarisoft-version = {{ lte_version }}
license-expiration = {{ lte_expiration }}
core-network-mac = {{ mac }}
{%- if slapparameter_dict.get("iperf3", 0) %}
iperf3-server-ipv4 = ${iperf-service-0:ip}
{%- endif %}
{%- for i in range(1, slapparameter_dict.get("iperf3", 0) + 1) %}
iperf3-server-{{ i - 1 }}-port = ${iperf-service-{{ i - 1 }}:port}
{%- endfor %}
amarisoft-version = {{ amarisoft['version']}}
amarisoft-host-id = {{ amarisoft['lteenb_host_id'] }}
amarisoft-available-versions = {{ amarisoft['version_installed'] }}
license-expiration = {{ amarisoft['ltemme_expiration'] }}
monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html
sim-list = {{ imsi_list | join(', ') }}
...
...
software/simpleran/instance-enb-input-schema.json
View file @
1685efc2
This diff is collapsed.
Click to expand it.
software/simpleran/instance-enb.jinja2.cfg
View file @
1685efc2
# instance-enb implements eNB/gNB service.
{#- defaults for global eNB/gNB parameters.
TODO automatically load enb defaults from JSON schema #}
{%- set enb_defaults = {
...
...
@@ -8,9 +7,44 @@
'use_ipv4': False,
'gnb_id_bits': 28,
'nssai': {'1': {'sst': 1}},
'handover_a1_rsrp': -70,
'handover_a1_hysteresis': 0,
'handover_a1_time_to_trigger': 640,
'handover_a2_rsrp': -80,
'handover_a2_hysteresis': 0,
'handover_a2_time_to_trigger': 640,
'handover_meas_gap_config': 'Gap Pattern 1',
'xlog_forwarding_enabled': True,
'wendelin_telecom_software_release_url': 'wendelin-telecom-enb-shared-instance',
'xlog_fluentbit_forward_port': 24224,
'nr_nr_handover': {
'event': {
'a3_rsrp': 6
},
'hysteresis': 0,
'time_to_trigger': 480
},
'nr_eutra_handover': {
'event': {
'b1_rsrp': -80
},
'hysteresis': 0,
'time_to_trigger': 100
},
'eutra_eutra_handover': {
'event': {
'a3_rsrp': 6
},
'hysteresis': 0,
'time_to_trigger': 480
},
'eutra_nr_handover': {
'event': {
'b1_rsrp': -80
},
'hysteresis': 0,
'time_to_trigger': 100
}
} %}
{%- set gtp_addr_lo = '127.0.1.1' %}
{%- for k,v in enb_defaults|dictsort %}
...
...
@@ -102,17 +136,15 @@ enb-radio-log = ${directory:log}/enb.log
enb-start-date = ${directory:run}/enb-start.date
inline =
#!/bin/sh
{% if not slapparameter_dict.get("testing", False) %}
# Amarisoft init scripts
sudo -n
/opt/amarisoft
/rm-tmp-lte
sudo -n
/opt/amarisoft/init-sdr
sudo -n
/opt/amarisoft
/init-enb
sudo -n
{{ amarisoft['dir'] }}
/rm-tmp-lte
sudo -n
{{ amarisoft['dir'] }}/init-sdr {{ amarisoft['dir'] }}/v{{ amarisoft['version'] }};
sudo -n
{{ amarisoft['dir'] }}
/init-enb
# Add useful information to enb-info log
(echo && echo && date "+[%Y/%m/%d %T.%N %Z] Starting eNB software...") >> ${:enb-info-log}
(echo -n "PCB: " ; for o in t b v s ; do sudo -n /opt/amarisoft/get-sdr-info -$o 2> /dev/null ; echo -n " " ; done ; echo) >> ${:enb-info-log}
(AMARISOFT_PATH=/dev/null {{ enb }}/lteenb ${directory:etc}/enb.cfg 2>&1 >/dev/null | sed -n 's/^.*\(Host ID.*\)$/\1/gp') >> ${:enb-info-log}
(echo -n "PCB: " ; for o in t b v s ; do sudo -n {{ sdr['dir'] }}/get-sdr-info -$o 2> /dev/null ; echo -n " " ; done ; echo) >> ${:enb-info-log}
echo "System info: $(uname -a)" >> ${:enb-info-log}
({{
sdr
}}/sdr_util version && echo) >> ${:enb-info-log}
({{
amarisoft['sdr_dir']
}}/sdr_util version && echo) >> ${:enb-info-log}
# Remove obsolete logs
rm -f ${directory:log}/enb-2024*
rm -f ${directory:log}/gnb*
...
...
@@ -129,8 +161,7 @@ inline =
tail -c 100M ${:enb-info-archive-log} > ${:enb-info-archive-log}.tmp
mv ${:enb-info-archive-log}.tmp ${:enb-info-archive-log}
# Launch lteenb
{{ enb }}/lteenb ${directory:etc}/enb.cfg >> ${:enb-info-log} 2>> ${:enb-info-log}
{% endif %}
{{ amarisoft['enb_dir'] }}/lteenb ${directory:etc}/enb.cfg >> ${:enb-info-log} 2>> ${:enb-info-log}
[enb-service]
recipe = slapos.cookbook:wrapper
...
...
@@ -144,7 +175,7 @@ hash-files =
${enb-sh-wrapper:output}
environment =
LD_LIBRARY_PATH={{ openssl_location }}/lib
AMARISOFT_PATH=
/opt/amarisoft/.amarisoft
AMARISOFT_PATH=
{{ amarisoft['license_dir'] }}
[xamari-xlog-script]
recipe = slapos.recipe.template
...
...
@@ -170,6 +201,19 @@ wrapper-path = ${directory:service}/${:_buildout_section_name_}
command-line = ${xamari-xlog-script:output}
hash-files = ${:command-line}
[request-parameters]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Wendelin Telecom Registration
software-url = {{ slapparameter_dict.wendelin_telecom_software_release_url }}
shared = true
{%- if not slapparameter_dict.xlog_forwarding_enabled or slapparameter_dict.get("xlog_fluentbit_forward_host") %}
state = destroyed
{%- else %}
config-fluentbit-tag = ${xlog-fluentbit-tag:xlog-fluentbit-tag}
return = gateway-host
{%- endif %}
[request-wendelin-telecom-shared]
<= slap-connection
recipe = slapos.cookbook:requestoptional
...
...
@@ -302,13 +346,16 @@ ipeercell_dict = {{ dumps(ipeercell_dict) }}
[publish-connection-information]
<= monitor-publish
recipe = slapos.cookbook:publish.serialised
websocket-
address = ${request-slave-frontend:connection-domain}/${nginx-params:websocket-path
}
websocket-port =
443
websocket-
hostname = ${frontend-urlparse:hostname
}
websocket-port =
${frontend-urlparse:port}
websocket-password = ${websocket-password:passwd}
enb-ipv6 = {{ my_ipv6 }}
enb-ipv4 = {{ lan_ipv4 }}
amarisoft-version = {{ lte_version }}
license-expiration = {{ lte_expiration }}
enb-mac = {{ mac }}
amarisoft-version = {{ amarisoft['version'] }}
amarisoft-host-id = {{ amarisoft['lteenb_host_id'] }}
amarisoft-available-versions = {{ amarisoft['version_installed'] }}
license-expiration = {{ amarisoft['lteenb_expiration'] }}
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) }}
...
...
@@ -334,7 +381,6 @@ name = ${:_buildout_section_name_}
[check-baseband-latency.py]
<= macro.promise
promise = check_baseband_latency
config-testing = {{ slapparameter_dict.get("testing", False) }}
config-amarisoft-stats-log = ${ru_amarisoft-stats-template:log-output}
config-stats-period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
config-min-rxtx-delay = {{ slapparameter_dict.get("min_rxtx_delay", 0) }}
...
...
software/simpleran/instance-ors-enb-input-schema.json
View file @
1685efc2
...
...
@@ -79,7 +79,7 @@
"mme_list"
:
{
"$ref"
:
"instance-enb-input-schema.json#/properties/mme_list"
,
"default"
:
{
"
1
"
:
{
"
Local core-network
"
:
{
"mme_addr"
:
"127.0.1.100"
}
}
...
...
@@ -88,20 +88,26 @@
"$ref"
:
"instance-enb-input-schema.json#/properties/plmn_list"
,
"description"
:
"List of PLMNs broadcasted by the eNodeB, at most 6 (default: 00101)"
,
"default"
:
{
"
1
"
:
{
"
Test PLMN
"
:
{
"plmn"
:
"00101"
}
}
},
"
lte_handover_a3_offset
"
:
{
"title"
:
"
A3 offset for LTE handover
"
,
"description"
:
"
RSRP gain offset between gNBs which will trigger handover
"
,
"
handover_a1_rsrp
"
:
{
"title"
:
"
Handover A1 event RSRP threshold
"
,
"description"
:
"
Integer, range from -140 to -43. RSRP threshold value in dBm.
"
,
"type"
:
"number"
,
"default"
:
6
"default"
:
-70
},
"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"
,
"handover_a1_hysteresis"
:
{
"title"
:
"Handover A1 event hysteresis"
,
"description"
:
"Integer, range from 0 to 30. A1 hysteresis in 0.5dB steps used for the measurement report triggering condition."
,
"type"
:
"number"
,
"default"
:
0
},
"handover_a1_time_to_trigger"
:
{
"title"
:
"Handover A1 event time to trigger"
,
"description"
:
"Time in ms during which the A1 event condition must be met before triggering the measurement report."
,
"type"
:
"number"
,
"enum"
:
[
0
,
...
...
@@ -121,29 +127,237 @@
2560
,
5120
],
"default"
:
480
"default"
:
640
},
"handover_a2_rsrp"
:
{
"title"
:
"Handover A2 event RSRP threshold"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold value in dBm."
,
"type"
:
"number"
,
"default"
:
-80
},
"handover_a2_hysteresis"
:
{
"title"
:
"Handover A2 event hysteresis"
,
"description"
:
"Integer, range from 0 to 30. A2 hysteresis in 0.5dB steps used for the measurement report triggering condition."
,
"type"
:
"number"
,
"default"
:
0
},
"handover_a2_time_to_trigger"
:
{
"title"
:
"Handover A2 event time to trigger"
,
"description"
:
"Time in ms during which the A2 event condition must be met before triggering the measurement report."
,
"type"
:
"number"
,
"enum"
:
[
0
,
40
,
64
,
80
,
100
,
128
,
160
,
256
,
320
,
480
,
512
,
640
,
1024
,
1280
,
2560
,
5120
],
"default"
:
640
},
"eutra_eutra_handover"
:
{
"title"
:
"EUTRA Handover"
,
"type"
:
"object"
,
"default"
:
{
"event"
:
{
"a3_rsrp"
:
6
},
"hysteresis"
:
0
,
"time_to_trigger"
:
480
},
"properties"
:
{
"event"
:
{
"title"
:
"EUTRA Handover event"
,
"type"
:
"object"
,
"oneOf"
:
[
{
"title"
:
"A3 event"
,
"type"
:
"object"
,
"required"
:
[
"a3_rsrp"
],
"properties"
:
{
"a3_rsrp"
:
{
"title"
:
"Handover A3 event RSRP offset"
,
"description"
:
"Integer, range from -140 to -43. RSRP gain offset between eNBs and gNBs which will trigger handover"
,
"type"
:
"number"
}
}
},
{
"title"
:
"A4 event"
,
"type"
:
"object"
,
"required"
:
[
"a4_rsrp"
],
"properties"
:
{
"a4_rsrp"
:
{
"title"
:
"Handover A4 event RSRP threshold"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold value in dBm"
,
"type"
:
"number"
}
}
},
{
"title"
:
"A5 event"
,
"type"
:
"object"
,
"required"
:
[
"a5_threshold1_rsrp"
,
"a5_threshold2_rsrp"
],
"properties"
:
{
"a5_threshold1_rsrp"
:
{
"title"
:
"Handover A5 event RSRP threshold1"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold1 value in dBm"
,
"type"
:
"number"
},
"a5_threshold2_rsrp"
:
{
"title"
:
"Handover A5 event RSRP threshold2"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold2 value in dBm"
,
"type"
:
"number"
}
}
}
]
},
"hysteresis"
:
{
"title"
:
"EUTRA Handover hysteresis"
,
"description"
:
"Integer, range from 0 to 30. A3/A4/A5 hysteresis in 0.5dB steps used for the measurement report triggering condition."
,
"type"
:
"number"
},
"time_to_trigger"
:
{
"title"
:
"EUTRA Handover time to trigger"
,
"description"
:
"Time in ms during which the A3/A4/A5 event condition must be met before triggering the measurement report."
,
"type"
:
"number"
,
"enum"
:
[
0
,
40
,
64
,
80
,
100
,
128
,
160
,
256
,
320
,
480
,
512
,
640
,
1024
,
1280
,
2560
,
5120
]
}
}
},
"eutra_nr_handover"
:
{
"title"
:
"NR Handover"
,
"type"
:
"object"
,
"default"
:
{
"event"
:
{
"b1_rsrp"
:
-80
},
"hysteresis"
:
0
,
"time_to_trigger"
:
100
},
"properties"
:
{
"event"
:
{
"title"
:
"NR Handover event"
,
"type"
:
"object"
,
"oneOf"
:
[
{
"title"
:
"B1 event"
,
"type"
:
"object"
,
"required"
:
[
"b1_rsrp"
],
"properties"
:
{
"b1_rsrp"
:
{
"title"
:
"Handover B1 event RSRP threshold"
,
"description"
:
"Integer, range from -156 to -30. RSRP threshold value in dBm."
,
"type"
:
"number"
}
}
},
{
"title"
:
"B2 event"
,
"type"
:
"object"
,
"required"
:
[
"b2_threshold1_rsrp"
,
"b2_threshold2_rsrp"
],
"properties"
:
{
"b2_threshold1_rsrp"
:
{
"title"
:
"Handover B2 event RSRP threshold1"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold1 value in dBm"
,
"type"
:
"number"
},
"b2_threshold2_rsrp"
:
{
"title"
:
"Handover B2 event RSRP threshold2"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold2 value in dBm"
,
"type"
:
"number"
}
}
}
]
},
"hysteresis"
:
{
"title"
:
"NR Handover hysteresis"
,
"description"
:
"Integer, range from 0 to 30. NR B1 or B2 hysteresis in 0.5dB steps."
,
"type"
:
"number"
},
"time_to_trigger"
:
{
"title"
:
"NR Handover time to trigger"
,
"description"
:
"Time in ms during which the NR B1 or B2 event condition must be met before triggering the measurement report."
,
"type"
:
"number"
,
"enum"
:
[
0
,
40
,
64
,
80
,
100
,
128
,
160
,
256
,
320
,
480
,
512
,
640
,
1024
,
1280
,
2560
,
5120
]
}
}
},
"handover_meas_gap_config"
:
{
"title"
:
"Handover measurement gap configuration"
,
"description"
:
"Configuration of the measurement gap. Ignored if no neighbour cells are configured."
,
"type"
:
"string"
,
"enum"
:
[
"None"
,
"Gap Pattern 0"
,
"Gap Pattern 1"
],
"default"
:
"Gap Pattern 1"
},
"ncell_list"
:
{
"title"
:
"Neighbour Cell Info"
,
"description"
:
"Neighbour Cell Info"
,
"patternProperties"
:
{
".*"
:
{
"properties"
:
{
"dl_earfcn"
:
{
"$ref"
:
"peer/cell/lte/input-schema.json#/properties/dl_earfcn"
},
"pci"
:
{
"$ref"
:
"peer/cell/lte/input-schema.json#/properties/pci"
},
"cell_id"
:
{
"$ref"
:
"peer/cell/lte/input-schema.json#/properties/e_cell_id"
},
"tac"
:
{
"$ref"
:
"peer/cell/lte/input-schema.json#/properties/tac"
,
"default"
:
"0x0001"
}
},
"type"
:
"object"
"$ref"
:
"peer/cell/input-schema.json"
}
},
"type"
:
"object"
,
...
...
software/simpleran/instance-ors-enb.jinja2.cfg
View file @
1685efc2
...
...
@@ -12,13 +12,22 @@
"n_antenna_ul": 2,
"rf_mode": "tdd",
"tdd_ul_dl_config": "[Configuration 2] 5ms 2UL 6DL (default)",
"pci": 1,
"cell_id": "0x01",
"enb_id": ors_id['enb_id'],
"cell_id": ors_id['enb_cell_id'],
"pci": ors_id['enb_pci'],
"root_sequence_index": ors_id['root_sequence_index'],
"tac": "0x0001",
"root_sequence_index": 204,
"enb_id": "0x1A2D0",
"mme_list": {'1': {'mme_addr': '127.0.1.100'}},
"plmn_list": {"1": {'plmn': '00101'}},
'mme_list': {
'Local Core Network': {
'mme_addr': '127.0.1.100'
}
},
'plmn_list': {
'Test PLNM': {
'plmn': '00101',
'tac': 100
}
},
"ncell_list": {},
"x2_peers": {},
"inactivity_timer": 10000,
...
...
@@ -31,12 +40,22 @@
"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": ors_id['gnb_id'],
"cell_id": ors_id['gnb_cell_id'],
"pci": ors_id['gnb_pci'],
"root_sequence_index": ors_id['root_sequence_index'],
"gnb_id_bits": 28,
"amf_list": {'1': {'amf_addr': '127.0.1.100'}},
"plmn_list": {'1': {'plmn': '00101', 'tac': 100}},
'amf_list': {
'Local Core Network': {
'amf_addr': '127.0.1.100'
}
},
'plmn_list': {
'Test PLNM': {
'plmn': '00101',
'tac': 100
}
},
"ncell_list": {},
"xn_peers": {},
"inactivity_timer": 10000,
...
...
@@ -95,7 +114,7 @@
'nr_band': ors_version['current-nr-band'],
'bandwidth': slapparameter_dict.nr_bandwidth,
'ssb_pos_bitmap': slapparameter_dict.ssb_pos_bitmap,
'root_sequence_index':
1
,
'root_sequence_index':
slapparameter_dict.root_sequence_index
,
}
%}
{%- endif %}
...
...
@@ -123,37 +142,10 @@
{#- 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,
'_':
peer
cell | tojson
'_':
n
cell | tojson
})
%}
{%- endfor %}
...
...
@@ -228,6 +220,16 @@ frequency-range-rating = {{ ors_version['range'] }}
current-tx-power-estimate = {{ ors_version['power-estimate'] }}
current-tx-gain = {{ ors_version['current-tx-gain'] }}
current-rx-gain = {{ ors_version['current-rx-gain'] }}
cell-id = {{ slapparameter_dict['cell_id'] }}
physical-cell-id = {{ slapparameter_dict['pci'] }}
root-sequence-index = {{ slapparameter_dict['root_sequence_index'] }}
{%- if enb_mode == "enb" %}
enb-id = {{ slapparameter_dict['enb_id'] }}
eutra-cell-id = {{ ors_id['eutra_cell_id'] }}
{%- else %}
gnb-id = {{ slapparameter_dict['gnb_id'] }}
nr-cell-id = {{ ors_id['nr_cell_id'] }}
{%- endif %}
{%- if enb_mode == 'enb' %}
current-frequency = {{ xearfcn_module.frequency(ors_version['current-earfcn']) }} MHz
...
...
software/simpleran/instance-ors-gnb-input-schema.json
View file @
1685efc2
...
...
@@ -60,7 +60,7 @@
"amf_list"
:
{
"$ref"
:
"instance-enb-input-schema.json#/properties/amf_list"
,
"default"
:
{
"
1
"
:
{
"
Local core-network
"
:
{
"amf_addr"
:
"127.0.1.100"
}
}
...
...
@@ -69,7 +69,7 @@
"$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
"
:
{
"
Test PLMN
"
:
{
"plmn"
:
"00101"
,
"tac"
:
100
}
...
...
@@ -78,15 +78,57 @@
"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
"
,
"
handover_a1_rsrp
"
:
{
"title"
:
"
Handover A1 event RSRP threshold
"
,
"description"
:
"
Integer, range from -140 to -43. RSRP threshold value in dBm.
"
,
"type"
:
"number"
,
"default"
:
6
"default"
:
-70
},
"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"
,
"handover_a1_hysteresis"
:
{
"title"
:
"Handover A1 event hysteresis"
,
"description"
:
"Integer, range from 0 to 30. A1 hysteresis in 0.5dB steps used for the measurement report triggering condition."
,
"type"
:
"number"
,
"default"
:
0
},
"handover_a1_time_to_trigger"
:
{
"title"
:
"Handover A1 event time to trigger"
,
"description"
:
"Time in ms during which the A1 event condition must be met before triggering the measurement report."
,
"type"
:
"number"
,
"enum"
:
[
0
,
40
,
64
,
80
,
100
,
128
,
160
,
256
,
320
,
480
,
512
,
640
,
1024
,
1280
,
2560
,
5120
],
"default"
:
640
},
"handover_a2_rsrp"
:
{
"title"
:
"Handover A2 event RSRP threshold"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold value in dBm."
,
"type"
:
"number"
,
"default"
:
-80
},
"handover_a2_hysteresis"
:
{
"title"
:
"Handover A2 event hysteresis"
,
"description"
:
"Integer, range from 0 to 30. A2 hysteresis in 0.5dB steps used for the measurement report triggering condition."
,
"type"
:
"number"
,
"default"
:
0
},
"handover_a2_time_to_trigger"
:
{
"title"
:
"Handover A2 event time to trigger"
,
"description"
:
"Time in ms during which the A2 event condition must be met before triggering the measurement report."
,
"type"
:
"number"
,
"enum"
:
[
0
,
...
...
@@ -106,38 +148,201 @@
2560
,
5120
],
"default"
:
100
"default"
:
640
},
"nr_nr_handover"
:
{
"title"
:
"NR Handover"
,
"type"
:
"object"
,
"default"
:
{
"event"
:
{
"a3_rsrp"
:
6
},
"hysteresis"
:
0
,
"time_to_trigger"
:
480
},
"properties"
:
{
"event"
:
{
"title"
:
"NR Handover event"
,
"type"
:
"object"
,
"oneOf"
:
[
{
"title"
:
"A3 event"
,
"type"
:
"object"
,
"required"
:
[
"a3_rsrp"
],
"properties"
:
{
"a3_rsrp"
:
{
"title"
:
"Handover A3 event RSRP offset"
,
"description"
:
"Integer, range from -140 to -43. RSRP gain offset between eNBs and gNBs which will trigger handover"
,
"type"
:
"number"
}
}
},
{
"title"
:
"A4 event"
,
"type"
:
"object"
,
"required"
:
[
"a4_rsrp"
],
"properties"
:
{
"a4_rsrp"
:
{
"title"
:
"Handover A4 event RSRP threshold"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold value in dBm"
,
"type"
:
"number"
}
}
},
{
"title"
:
"A5 event"
,
"type"
:
"object"
,
"required"
:
[
"a5_threshold1_rsrp"
,
"a5_threshold2_rsrp"
],
"properties"
:
{
"a5_threshold1_rsrp"
:
{
"title"
:
"Handover A5 event RSRP threshold1"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold1 value in dBm"
,
"type"
:
"number"
},
"a5_threshold2_rsrp"
:
{
"title"
:
"Handover A5 event RSRP threshold2"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold2 value in dBm"
,
"type"
:
"number"
}
}
}
]
},
"hysteresis"
:
{
"title"
:
"NR Handover hysteresis"
,
"description"
:
"Integer, range from 0 to 30. A3/A4/A5 hysteresis in 0.5dB steps used for the measurement report triggering condition."
,
"type"
:
"number"
},
"time_to_trigger"
:
{
"title"
:
"NR Handover time to trigger"
,
"description"
:
"Time in ms during which the A3/A4/A5 event condition must be met before triggering the measurement report."
,
"type"
:
"number"
,
"enum"
:
[
0
,
40
,
64
,
80
,
100
,
128
,
160
,
256
,
320
,
480
,
512
,
640
,
1024
,
1280
,
2560
,
5120
]
}
}
},
"nr_eutra_handover"
:
{
"title"
:
"EUTRA Handover"
,
"type"
:
"object"
,
"default"
:
{
"event"
:
{
"b1_rsrp"
:
-80
},
"hysteresis"
:
0
,
"time_to_trigger"
:
100
},
"properties"
:
{
"event"
:
{
"title"
:
"EUTRA Handover event"
,
"type"
:
"object"
,
"oneOf"
:
[
{
"title"
:
"B1 event"
,
"type"
:
"object"
,
"required"
:
[
"b1_rsrp"
],
"properties"
:
{
"b1_rsrp"
:
{
"title"
:
"Handover B1 event RSRP threshold"
,
"description"
:
"Integer, range from -156 to -30. RSRP threshold value in dBm."
,
"type"
:
"number"
}
}
},
{
"title"
:
"B2 event"
,
"type"
:
"object"
,
"required"
:
[
"b2_threshold1_rsrp"
,
"b2_threshold2_rsrp"
],
"properties"
:
{
"b2_threshold1_rsrp"
:
{
"title"
:
"Handover B2 event RSRP threshold1"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold1 value in dBm"
,
"type"
:
"number"
},
"b2_threshold2_rsrp"
:
{
"title"
:
"Handover B2 event RSRP threshold2"
,
"description"
:
"Integer, range from -140 to -43. RSRP threshold2 value in dBm"
,
"type"
:
"number"
}
}
}
]
},
"hysteresis"
:
{
"title"
:
"EUTRA Handover hysteresis"
,
"description"
:
"Integer, range from 0 to 30. EUTRA B1 or B2 hysteresis in 0.5dB steps."
,
"type"
:
"number"
},
"time_to_trigger"
:
{
"title"
:
"EUTRA Handover time to trigger"
,
"description"
:
"Time in ms during which the EUTRA B1 or B2 event condition must be met before triggering the measurement report."
,
"type"
:
"number"
,
"enum"
:
[
0
,
40
,
64
,
80
,
100
,
128
,
160
,
256
,
320
,
480
,
512
,
640
,
1024
,
1280
,
2560
,
5120
]
}
}
},
"handover_meas_gap_config"
:
{
"title"
:
"Handover measurement gap configuration"
,
"description"
:
"Configuration of the measurement gap. Ignored if no neighbour cells are configured."
,
"type"
:
"string"
,
"enum"
:
[
"None"
,
"Gap Pattern 0"
,
"Gap Pattern 1"
],
"default"
:
"Gap Pattern 1"
},
"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"
"$ref"
:
"peer/cell/input-schema.json"
}
},
"type"
:
"object"
,
...
...
software/simpleran/instance-ors-ue.jinja2.cfg
View file @
1685efc2
...
...
@@ -4,7 +4,8 @@
"n_antenna_ul": 1,
"rf_mode": "tdd",
"plmn": "00101",
"disable_sdr": false
"disable_sdr": false,
"power_on": true
} %}
{%- for k,v in ors_defaults|dictsort %}
...
...
software/simpleran/instance-ors.cfg
View file @
1685efc2
...
...
@@ -48,6 +48,7 @@ import-list +=
[ors-version]
recipe = slapos.recipe.build
configuration = $${slap-configuration:configuration}
sdr-dir = $${sdr:dir}
init =
import subprocess
range_map = {
...
...
@@ -58,8 +59,8 @@ init =
"B41": "2496MHz - 2690MHz",
"B42": "3400MHz - 3600MHz",
"B43": "3600MHz - 3800MHz",
"N77": "3
300MHz - 42
00MHz",
"N79": "4
4
00MHz - 5000MHz",
"N77": "3
800MHz - 40
00MHz",
"N79": "4
6
00MHz - 5000MHz",
"UNKNOWN": "Information not available for this band",
}
default_tx_gain_map = {
...
...
@@ -166,14 +167,14 @@ init =
}
def get_sdr_info(cmd):
if options['configuration'].get('testing', False):
return {'t': 'TDD', 'b': 'B39', 'v': '4.2', 's': 'B53'}[cmd]
.encode()
return {'t': 'TDD', 'b': 'B39', 'v': '4.2', 's': 'B53'}[cmd]
return subprocess.check_output(
["sudo", "-n",
"/opt/amarisoft
/get-sdr-info", "-" + cmd]
)
version = get_sdr_info('v')
.decode()
["sudo", "-n",
options['sdr-dir'] + "
/get-sdr-info", "-" + cmd]
)
.decode()
version = get_sdr_info('v')
options['version'] = float(version) if version != 'UNKNOWN' else 0
options['band'] = get_sdr_info('b')
.decode()
options['tdd'] = get_sdr_info('t')
.decode()
options['band'] = get_sdr_info('b')
options['tdd'] = get_sdr_info('t')
options['one-watt'] = bool(options['version'] >= 4)
options['ors-version'] = "{} {} {}".format(
options['tdd'],
...
...
software/simpleran/instance-ue.jinja2.cfg
View file @
1685efc2
# instance-ue implements UEsim service.
#
{#- defaults for global UE parameters.
TODO automatically load ue defaults from JSON schema #}
{%- set ue_defaults = {
...
...
@@ -15,6 +14,8 @@ parts =
directory
lte-ue-config
lte-ue-service
nginx-launcher
nginx-graceful
monitor-base
publish-connection-information
...
...
@@ -76,21 +77,19 @@ ue-radio-log = ${directory:log}/ue.log
ue-start-date = ${directory:run}/enb-start.date
inline =
#!/bin/sh
{% if not slapparameter_dict.get("testing", False) %}
sudo /opt/amarisoft/rm-tmp-lte | true;
sudo -n /opt/amarisoft/init-sdr;
sudo -n /opt/amarisoft/init-ue;
sudo {{ amarisoft['dir'] }}/rm-tmp-lte | true;
sudo -n {{ amarisoft['dir'] }}/init-sdr {{ amarisoft['dir'] }}/v{{ amarisoft['version'] }};
sudo -n {{ amarisoft['dir'] }}/init-ue;
stat ${:ue-start-date} && mv ${:ue-radio-log} ${directory:log}/ue-$(cat ${:ue-start-date}).log
rm -f $(ls -1t ${directory:log}/ue-2* | tail -n+50)
date +"%Y-%m-%d-%T" > ${:ue-start-date}
(echo && echo && date "+[%Y/%m/%d %T.%N %Z] Starting UE software..." && echo) >> ${:ue-log};
tail -c 1M ${:ue-log} > ${:ue-log}.tmp;
mv ${:ue-log}.tmp ${:ue-log};
{%- if
ors
%}
echo "power_on" | sudo -n {{
ue
}}/lteue ${directory:etc}/ue.cfg >> ${:ue-log} 2>> ${:ue-log};
{%- if
slapparameter_dict.get('power_on', False)
%}
echo "power_on" | sudo -n {{
amarisoft['ue_dir']
}}/lteue ${directory:etc}/ue.cfg >> ${:ue-log} 2>> ${:ue-log};
{%- else %}
{{ ue }}/lteue ${directory:etc}/ue.cfg >> ${:ue-log} 2>> ${:ue-log};
{%- endif %}
{{ amarisoft['ue_dir'] }}/lteue ${directory:etc}/ue.cfg >> ${:ue-log} 2>> ${:ue-log};
{%- endif %}
### User Equipment (UE)
...
...
@@ -106,7 +105,7 @@ hash-files =
${lte-ue-sh-wrapper:output}
environment =
LD_LIBRARY_PATH={{ openssl_location }}/lib
AMARISOFT_PATH=
/opt/amarisoft/.amarisoft
AMARISOFT_PATH=
{{ amarisoft['license_dir'] }}
[config-base]
recipe = slapos.recipe.template:jinja2
...
...
@@ -142,9 +141,15 @@ iue_dict = {{ dumps(iue_dict) }}
<= monitor-publish
recipe = slapos.cookbook:publish.serialised
rue_bind_addr = {{my_ipv6}}
websocket-address = ${request-slave-frontend:connection-domain}/${nginx-params:websocket-path}
websocket-port = 443
ue-ipv4 = {{ lan_ipv4 }}
ue-mac = {{ mac }}
websocket-hostname = ${frontend-urlparse:hostname}
websocket-port = ${frontend-urlparse:port}
websocket-password = ${websocket-password:passwd}
amarisoft-version = {{ amarisoft['version'] }}
amarisoft-host-id = {{ amarisoft['lteue_host_id'] }}
amarisoft-available-versions = {{ amarisoft['version_installed'] }}
license-expiration = {{ amarisoft['lteenb_expiration'] }}
monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html
[monitor-instance-parameter]
...
...
software/simpleran/instance.cfg
View file @
1685efc2
...
...
@@ -39,7 +39,8 @@ context =
raw pythonwitheggs ${buildout:bin-directory}/pythonwitheggs
section slap_connection slap-connection
key slapparameter_dict slap-configuration:configuration
key lan_ipv4 lan-ip:ipv4
key lan_ipv4 lan:ipv4
key mac lan:mac
key my_ipv4 slap-configuration:ipv4-random
key my_ipv6 slap-configuration:ipv6-random
raw nginx_template ${nginx_conf.in:target}
...
...
@@ -80,39 +81,73 @@ init =
assert 'xbuildout' not in sys.modules
sys.modules['xbuildout'] = xbuildout
[sdr]
recipe = slapos.recipe.build
configuration = $${slap-configuration:configuration}
init =
# Set SDR directory
options['dir'] = options['configuration'].get('sdr_dir', '/opt/sdr')
[amarisoft]
recipe = slapos.recipe.build
fixed_version = 2024-11-21.1732633257
configuration = $${slap-configuration:configuration}
init =
import os, re
mock = options['configuration'].get('lte_mock', False)
# Set Amarisoft directory
options['dir'] = options['configuration'].get('amarisoft_dir', '/opt/amarisoft')
# Get Available Amarisoft versions
if mock:
version_installed = [options['fixed_version']]
else:
version_installed = [x[1:] for x in os.listdir(options['dir']) if re.match(r"v[0-9]{4}-[0-9]{2}-[0-9]{2}.[0-9]{10}", x)]
options['version_installed'] = ', '.join(version_installed)
# Set Amarisoft version to use
slapconf_version = options['configuration'].get('amarisoft_version', False)
if slapconf_version and \
slapconf_version in version_installed:
options['version'] = slapconf_version
else:
options['version'] = options['fixed_version']
# Set Binaries and license directories
binary_dir = options['dir'] + "/v" + options['version']
options['license_dir'] = options['dir'] + '/.amarisoft'
options['sdr_dir'] = binary_dir + '/trx_sdr'
options['enb_dir'] = binary_dir + '/enb'
options['mme_dir'] = binary_dir + '/mme'
options['ims_dir'] = binary_dir + '/mme'
options['ue_dir'] = binary_dir + '/ue'
if options['configuration'].get('lte_mock', False):
options['enb_dir'] = '${buildout:directory}/bin'
options['mme_dir'] = '${buildout:directory}/bin'
options['ims_dir'] = '${buildout:directory}/bin'
options['ue_dir'] = '${buildout:directory}/bin'
# Get License expiration and host IDs
if mock:
options.update({'lteenb_expiration': '9999-99-99', 'ltemme_expiration': '9999-99-99', 'lteue_expiration': '9999-99-99'})
options.update({'lteenb_host_id': '00-00-00-00-00-00-00-00', 'ltemme_host_id': '00-00-00-00-00-00-00-00', 'lteue_host_id': '00-00-00-00-00-00-00-00'})
else:
options.update({'lteenb_expiration': 'Unknown', 'ltemme_expiration': 'Unknown', 'lteue_expiration': 'Unknown'})
options.update({'lteenb_host_id': 'Unknown', 'ltemme_host_id': 'Unknown', 'lteue_host_id': 'Unknown'})
try:
lte_version = sorted(filter(lambda x: re.match(r"v[0-9]{4}-[0-9]{2}-[0-9]{2}", x), os.listdir('/opt/amarisoft')))[-1][1:]
except FileNotFoundError:
lte_version = 'LTEVERSION'
path = "/opt/amarisoft/v" + lte_version
options['lte-version'] = lte_version
options['path'] = path
options['sdr'] = path + "/trx_sdr"
options['enb'] = path + "/enb"
options['mme'] = path + "/mme"
options['ims'] = path + "/mme"
options['ue'] = path + "/ue"
import os
lte_expiration = "Unknown"
amarisoft_dir = '/opt/amarisoft/.amarisoft'
try:
for filename in os.listdir(amarisoft_dir):
for filename in os.listdir(options['license_dir']):
if filename.endswith('.key'):
with open(os.path.join(
amarisoft_dir
, filename), 'r') as f:
with open(os.path.join(
options['license_dir']
, filename), 'r') as f:
f.seek(260)
for l in f:
if l.startswith('host_id='):
host_id = l.split('=')[1].strip()
if l.startswith('product_id='):
product_id = l.split('=')[1].strip()
if l.startswith('version='):
lte_expiration = l.split('=')[1].strip()
expiration = l.split('=')[1].strip()
options[product_id + '_expiration'] = expiration
options[product_id + '_host_id'] = host_id
except FileNotFoundError:
pass
options['lte-expiration'] = lte_expiration
[lan
-ip
]
[lan]
recipe = slapos.recipe.build
init =
import netifaces
...
...
@@ -124,6 +159,45 @@ init =
options['ipv4'] = a[netifaces.AF_INET][0]['addr']
except:
options['ipv4'] = "0.0.0.0"
try:
options['mac'] = a[netifaces.AF_LINK][0]['addr']
except:
options['mac'] = "00:00:00:00:00:00"
[ors-id]
recipe = slapos.recipe.build
configuration = $${slap-configuration:configuration}
init =
import socket
try:
sn = int(socket.gethostname().split('ors')[1])
except (IndexError, ValueError):
sn = 0
options['serial_number'] = sn
options['enb_id'] = "0x{:05X}".format(sn % 2**20)
options['gnb_id'] = "0x{:05X}".format((sn + 2**19) % 2**20)
options['enb_pci'] = sn % 504
options['gnb_pci'] = sn % 1008
options['enb_cell_id'] = "0x{:02X}".format(sn % 2**8)
options['gnb_cell_id'] = "0x{:02X}".format((sn + 2**7) % 2**8)
options['root_sequence_index'] = sn % 834
def to_int(x):
try:
if '0x' in enb_id:
return int(x, 16)
return int(x)
except ValueError:
return 0
enb_id = options['configuration'].get('enb_id', options['enb_id'])
gnb_id = options['configuration'].get('enb_id', options['enb_id'])
cell_id = options['configuration'].get('cell_id', options['enb_cell_id'])
gnb_id_bits = options['configuration'].get('gnb_id_bits', 28)
options['eutra_cell_id'] = \
"0x{:07X}".format(to_int(enb_id) * 2**8 + to_int(cell_id))
options['nr_cell_id'] = \
"0x{:07X}".format(to_int(gnb_id) * 2**(36 - gnb_id_bits) + to_int(cell_id))
[comp-id]
recipe = slapos.recipe.build
...
...
@@ -151,10 +225,9 @@ extra-context =
raw monitor_template ${monitor2-template:output}
section comp_id comp-id
section slap_configuration slap-configuration
key lte_version amarisoft:lte-version
key lte_expiration amarisoft:lte-expiration
key enb amarisoft:enb
key sdr amarisoft:sdr
section amarisoft amarisoft
section ors_id ors-id
section sdr sdr
raw enb_template ${enb.jinja2.cfg:target}
raw slaplte_template ${slaplte.jinja2:target}
raw drb_lte_template ${drb_lte.jinja2.cfg:target}
...
...
@@ -178,10 +251,8 @@ filename = instance-core-network.cfg
extensions = jinja2.ext.do
extra-context =
raw monitor_template ${monitor2-template:output}
key lte_version amarisoft:lte-version
key lte_expiration amarisoft:lte-expiration
key mme amarisoft:mme
key ims amarisoft:ims
section amarisoft amarisoft
section sdr sdr
raw mme_template ${mme.jinja2.cfg:target}
raw dnsmasq_template ${dnsmasq-core-network.jinja2.cfg:target}
raw ims_template ${ims.jinja2.cfg:target}
...
...
@@ -202,13 +273,12 @@ filename = instance-ue.cfg
extensions = jinja2.ext.do
extra-context =
section slap_configuration slap-configuration
section amarisoft amarisoft
section sdr sdr
raw monitor_template ${monitor2-template:output}
key ue amarisoft:ue
key sdr amarisoft:sdr
raw ue_template ${ue.jinja2.cfg:target}
raw slaplte_template ${slaplte.jinja2:target}
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_tapsplit ${ru_tapsplit:target}
...
...
software/simpleran/peer/cell/common.json
View file @
1685efc2
...
...
@@ -6,7 +6,8 @@
"cell_type"
,
"cell_kind"
,
"pci"
,
"tac"
"tac"
,
"plmn"
],
"properties"
:
{
"cell_type"
:
{
...
...
software/simpleran/peer/cell/lte/input-schema.json
View file @
1685efc2
...
...
@@ -8,13 +8,17 @@
"pci"
,
"tac"
,
"e_cell_id"
,
"dl_earfcn"
"dl_earfcn"
,
"plmn"
],
"properties"
:
{
"cell_type"
:
{
"$ref"
:
"../../../peer/cell/common.json#/properties/cell_type"
,
"const"
:
"lte"
},
"cell_kind"
:
{
"$ref"
:
"../../../peer/cell/common.json#/properties/cell_kind"
},
"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."
,
...
...
@@ -28,6 +32,11 @@
},
"tac"
:
{
"$ref"
:
"../../../cell/lte/input-schema.json#/properties/tac"
},
"plmn"
:
{
"title"
:
"Public Land Mobile Network"
,
"description"
:
"Public Land Mobile Network"
,
"type"
:
"string"
}
}
}
software/simpleran/peer/cell/nr/input-schema.json
View file @
1685efc2
...
...
@@ -10,13 +10,17 @@
"nr_cell_id"
,
"gnb_id_bits"
,
"dl_nr_arfcn"
,
"nr_band"
"nr_band"
,
"plmn"
],
"properties"
:
{
"cell_type"
:
{
"$ref"
:
"../../../peer/cell/common.json#/properties/cell_type"
,
"const"
:
"nr"
},
"cell_kind"
:
{
"$ref"
:
"../../../peer/cell/common.json#/properties/cell_kind"
},
"nr_cell_id"
:
{
"title"
:
"NR Cell ID"
,
"description"
:
"Concatenation of gnb_id and cell_id of the neighbour cell"
,
...
...
@@ -44,6 +48,11 @@
},
"tac"
:
{
"$ref"
:
"../../../cell/nr/input-schema.json#/$defs/tac"
},
"plmn"
:
{
"title"
:
"Public Land Mobile Network"
,
"description"
:
"Public Land Mobile Network"
,
"type"
:
"string"
}
}
}
software/simpleran/ru/amarisoft-rf-info.jinja2.py
View file @
1685efc2
#!{{ python_path }}
import
json
import
hashlib
import
hmac
import
logging
from
logging.handlers
import
RotatingFileHandler
import
time
...
...
@@ -18,14 +20,22 @@ class enbWebSocket:
handler
.
setFormatter
(
formatter
)
self
.
logger
.
addHandler
(
handler
)
if
{{
testing
}}:
return
self
.
ws_url
=
"{{ ws_url }}"
self
.
ws_password
=
"{{ ws_password }}"
self
.
ws
=
create_connection
(
self
.
ws_url
)
self
.
ws
=
create_connection
(
"{{ ws_url }}"
)
# Password authentication
data
=
json
.
loads
(
self
.
ws
.
recv
())
res
=
hmac
.
new
(
"{}:{}:{}"
.
format
(
data
[
'type'
],
self
.
ws_password
,
data
[
'name'
]).
encode
(),
msg
=
data
[
'challenge'
].
encode
(),
digestmod
=
hashlib
.
sha256
).
hexdigest
()
msg
=
{
"message"
:
"authenticate"
,
"res"
:
res
}
self
.
ws
.
send
(
json
.
dumps
(
msg
))
self
.
ws
.
recv
()
def
close
(
self
):
if
{{
testing
}}:
return
self
.
ws
.
close
()
def
send
(
self
,
msg
):
...
...
@@ -37,17 +47,11 @@ class enbWebSocket:
return
r
def
stats
(
self
):
if
{{
testing
}}:
r
=
{
'message'
:
'rf'
,
'rf_info'
:
"CPRI: x16 HW SW
\
n
"
}
else
:
self
.
send
({
"message"
:
"rf"
,
"rf_info"
:
True
})
r
=
self
.
recv
(
'rf'
)
self
.
send
({
"message"
:
"rf"
,
"rf_info"
:
True
})
r
=
self
.
recv
(
'rf'
)
self
.
logger
.
info
(
'RF info'
,
extra
=
{
'data'
:
json
.
dumps
(
r
)})
if
__name__
==
'__main__'
:
...
...
software/simpleran/ru/amarisoft-stats.jinja2.py
View file @
1685efc2
...
...
@@ -20,13 +20,11 @@ class enbWebSocket:
handler
.
setFormatter
(
formatter
)
self
.
logger
.
addHandler
(
handler
)
if
{{
testing
}}:
return
self
.
ws_url
=
"{{ ws_url }}"
self
.
ws_password
=
"{{ ws_password }}"
self
.
ws
=
create_connection
(
self
.
ws_url
)
# Password authentication
data
=
json
.
loads
(
self
.
ws
.
recv
())
res
=
hmac
.
new
(
"{}:{}:{}"
.
format
(
data
[
'type'
],
self
.
ws_password
,
data
[
'name'
]).
encode
(),
...
...
@@ -38,8 +36,6 @@ class enbWebSocket:
self
.
ws
.
recv
()
def
close
(
self
):
if
{{
testing
}}:
return
self
.
ws
.
close
()
def
send
(
self
,
msg
):
...
...
@@ -51,21 +47,12 @@ class enbWebSocket:
return
r
def
stats
(
self
):
if
{{
testing
}}:
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
=
{
'message'
:
'stats'
,
'samples'
:
{
'rx'
:
rxv
}
}
else
:
self
.
send
({
"message"
:
"stats"
,
"samples"
:
True
,
"rf"
:
True
})
r
=
self
.
recv
(
'stats'
)
self
.
send
({
"message"
:
"stats"
,
"samples"
:
True
,
"rf"
:
True
})
r
=
self
.
recv
(
'stats'
)
self
.
logger
.
info
(
'Samples stats'
,
extra
=
{
'data'
:
json
.
dumps
(
r
)})
if
__name__
==
'__main__'
:
...
...
software/simpleran/ru/libinstance.jinja2.cfg
View file @
1685efc2
...
...
@@ -196,7 +196,7 @@ hash-files =
{%- 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
config-sdr = {{
sdr
}}
config-sdr = {{
amarisoft['sdr_dir']
}}
config-sdr_dev = {{ n }}
config-dma_chan = 0
{%- endfor %}
...
...
@@ -204,7 +204,7 @@ config-dma_chan = 0
{%- elif ru.ru_link_type == 'cpri' %}
{{ promise('%s-sdr-busy' % ru_ref) }}
promise = check_sdr_busy
config-sdr = {{
sdr
}}
config-sdr = {{
amarisoft['sdr_dir']
}}
config-sdr_dev = {{ ru.cpri_link.sdr_dev }}
config-dma_chan = {{ ru.cpri_link.sfp_port }}
...
...
@@ -327,7 +327,7 @@ context =
key slapparameter_dict myslap:parameter_dict
key log_file :log-output
raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
raw
testing {{ testing }
}
raw
ws_password ${websocket-password:passwd
}
raw ws_url ws://{{ slapparameter_dict.com_addr }}:{{ slapparameter_dict.com_ws_port }}
raw python_path {{ buildout_directory}}/bin/pythonwitheggs
mode = 0775
...
...
@@ -353,7 +353,6 @@ context =
raw ws_password ${websocket-password:passwd}
raw ws_url ws://{{ slapparameter_dict.com_addr }}:{{ slapparameter_dict.com_ws_port }}
raw stats_period {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
raw testing {{ testing }}
raw python_path {{ buildout_directory}}/bin/pythonwitheggs
key iru_dict :iru_dict
iru_dict = {{ dumps(iru_dict) }}
...
...
@@ -460,14 +459,21 @@ cert-file = ${directory:etc}/websocket.crt
executable = {{ nginx_executable }}
wrapper = ${directory:bin}/nginx-with-ca
{%- if not slapparameter_dict.get("testing", False) %}
[frontend-urlparse]
recipe = slapos.recipe.build
domain = ${request-slave-frontend:connection-domain}
init =
import six.moves.urllib.parse as urlparse
parsed_url = urlparse.urlparse('wss://' + options['domain'])
options['hostname'] = parsed_url.hostname
options['port'] = parsed_url.port if parsed_url.port else 443
{{ part('websocket-promise') }}
<= monitor-promise-base
promise = check_socket_listening
name = websocket_promise.py
config-host = ${request-slave-frontend:connection-domain}
config-port = 443
{%- endif %}
config-host = ${frontend-urlparse:hostname}
config-port = ${frontend-urlparse:port}
{{ part('amarisoft-stats-service') }}
recipe = slapos.cookbook:wrapper
...
...
software/simpleran/slaplte.jinja2
View file @
1685efc2
...
...
@@ -383,6 +383,7 @@
{%- set ipeercell = ishared %}
{%- if _.cell_type == 'lte' %}
{%- do _.setdefault('ul_earfcn', J(jdefault_ul_earfcn(_.dl_earfcn))) %}
{%- do _.setdefault('lte_band', xearfcn_module.band(_.dl_earfcn)[0]["band"]) %}
{%- elif _.cell_type == 'nr' %}
{%- do _.setdefault('ul_nr_arfcn', J(jdefault_ul_nr_arfcn(_.dl_nr_arfcn, _.nr_band))) %}
{%- do _.setdefault('subcarrier_spacing',
...
...
software/simpleran/software.cfg
View file @
1685efc2
...
...
@@ -49,6 +49,7 @@ parts +=
dnsmasq
eggs
xamari
amarisoft-lte-mock-scripts
setcap-dnsmasq
# unimplemented parts - the http monitor and better log handling using logrotate
# apache-php
...
...
@@ -168,6 +169,31 @@ eggs =
netaddr
interpreter = pythonwitheggs
[amarisoft-lte-mock-repository]
recipe = slapos.recipe.build:gitclone
repository = https://lab.nexedi.com/nexedi/amarisoft-lte-mock.git
revision = 1.1
git-executable = ${git:location}/bin/git
[amarisoft-lte-mock]
recipe = zc.recipe.egg:develop
setup = ${amarisoft-lte-mock-repository:location}
egg = amarisoft-lte-mock
depends =
[amarisoft-lte-mock-scripts]
recipe = zc.recipe.egg
eggs =
${amarisoft-lte-mock:egg}
pcpp
PyYAML
websockets
scripts =
lteenb
ltemme
lteims
lteue
[xlte-repository]
recipe = slapos.recipe.build:gitclone
repository = https://lab.nexedi.com/kirr/xlte.git
...
...
@@ -201,3 +227,4 @@ websocket-client = 1.4.2
ncclient = 0.6.13
xmltodict = 0.13.0
nrarfcn = 2.4.0:whl
pcpp = 1.30
software/simpleran/test/test.py
View file @
1685efc2
...
...
@@ -104,20 +104,22 @@ def TAC(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
):
def
LTE_PEER
(
e_cell_id
,
pci
,
tac
,
plmn
):
return
{
'cell_kind'
:
'enb_peer'
,
'e_cell_id'
:
'0x%07x'
%
e_cell_id
,
'pci'
:
pci
,
'tac'
:
'0x%x'
%
tac
,
'plmn'
:
plmn
,
}
def
NR_PEER
(
nr_cell_id
,
gnb_id_bits
,
pci
,
tac
):
def
NR_PEER
(
nr_cell_id
,
gnb_id_bits
,
pci
,
tac
,
plmn
):
return
{
'cell_kind'
:
'enb_peer'
,
'nr_cell_id'
:
'0x%09x'
%
nr_cell_id
,
'gnb_id_bits'
:
gnb_id_bits
,
'pci'
:
pci
,
'tac'
:
tac
,
'plmn'
:
plmn
,
}
# X2_PEER/XN_PEER return basic parameters to indicate an LTE/NR ENB peer.
...
...
@@ -311,6 +313,7 @@ class ENBTestCase4(RFTestCase4):
def
getInstanceParameterDict
(
cls
):
return
{
'_'
:
json
.
dumps
({
'testing'
:
True
,
'lte_mock'
:
True
,
'enb_id'
:
'0x17'
,
'gnb_id'
:
'0x23'
,
'gnb_id_bits'
:
30
,
...
...
@@ -344,13 +347,13 @@ class ENBTestCase4(RFTestCase4):
_
(
'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
))
_
(
'PEERCELL4'
,
LTE
(
700
)
|
LTE_PEER
(
0x12345
,
35
,
0x123
,
"00101"
))
_
(
'PEERCELL5'
,
NR
(
520000
,
38
)
|
NR_PEER
(
0x77712
,
22
,
75
,
0x321
,
"00101"
))
cls
.
ho_inter
=
[
dict
(
rat
=
'eutra'
,
cell_id
=
0x12345
,
n_id_cell
=
35
,
dl_earfcn
=
700
,
tac
=
0x123
),
dict
(
rat
=
'eutra'
,
cell_id
=
0x12345
,
n_id_cell
=
35
,
dl_earfcn
=
700
,
tac
=
0x123
,
plmn
=
"00101"
),
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
),
tac
=
0x321
,
plmn
=
"00101"
),
]
def
CELLcfg
(
i
):
...
...
@@ -587,6 +590,7 @@ class UEsimTestCase4(RFTestCase4):
def
getInstanceParameterDict
(
cls
):
return
{
'_'
:
json
.
dumps
({
'testing'
:
True
,
'lte_mock'
:
True
,
})}
@
classmethod
...
...
software/simpleran/test/test_ors.py
View file @
1685efc2
...
...
@@ -41,8 +41,10 @@ setUpModule, ORSTestCase = makeModuleSetUpAndTestCaseClass(
param_dict
=
{
'testing'
:
True
,
'lte_mock'
:
True
,
'tx_gain'
:
17
,
'rx_gain'
:
17
,
'cell_id'
:
'0x01'
,
'pci'
:
250
,
'tac'
:
'0x1717'
,
'root_sequence_index'
:
'1'
,
...
...
@@ -53,26 +55,58 @@ param_dict = {
'inactivity_timer'
:
17
,
'ncell_list'
:
{
'ORS1'
:
{
'dl_earfcn'
:
40000
,
'dl_nr_arfcn'
:
403500
,
'ssb_nr_arfcn'
:
403500
,
'cell_type'
:
'lte'
,
'cell_kind'
:
'enb_peer'
,
'rat'
:
'eutra'
,
'dl_earfcn'
:
38450
,
'pci'
:
1
,
'n
r_cell_id'
:
'0x0000001'
,
'n
_id_cell'
:
1
,
'cell_id'
:
'0x0000001'
,
'
gnb_id_bits'
:
28
,
'
nr_band'
:
34
,
'
tac'
:
1
'
e_cell_id'
:
'0x0000001'
,
'
tac'
:
1
,
'
plmn'
:
"00101"
},
'ORS2'
:
{
'dl_earfcn'
:
50000
,
'dl_nr_arfcn'
:
519000
,
'ssb_nr_arfcn'
:
519000
,
'cell_type'
:
'lte'
,
'cell_kind'
:
'enb_peer'
,
'rat'
:
'eutra'
,
'dl_earfcn'
:
38050
,
'pci'
:
2
,
'n_id_cell'
:
2
,
'cell_id'
:
'0x0000002'
,
'e_cell_id'
:
'0x0000002'
,
'tac'
:
1
,
'plmn'
:
"00101"
},
'ORS3'
:
{
'cell_type'
:
'nr'
,
'cell_kind'
:
'enb_peer'
,
'rat'
:
'nr'
,
'dl_nr_arfcn'
:
520000
,
'ssb_nr_arfcn'
:
520000
,
'ul_nr_arfcn'
:
520000
,
'pci'
:
1
,
'n_id_cell'
:
1
,
'nr_cell_id'
:
'0x0000001'
,
'gnb_id_bits'
:
28
,
'nr_band'
:
41
,
'tac'
:
1
,
'plmn'
:
"00101"
},
'ORS4'
:
{
'cell_type'
:
'nr'
,
'cell_kind'
:
'enb_peer'
,
'rat'
:
'nr'
,
'dl_nr_arfcn'
:
380000
,
'ssb_nr_arfcn'
:
380000
,
'ul_nr_arfcn'
:
380000
,
'pci'
:
2
,
'n_id_cell'
:
2
,
'nr_cell_id'
:
'0x0000002'
,
'cell_id'
:
'0x0000001'
,
'gnb_id_bits'
:
30
,
'nr_band'
:
38
,
'tac'
:
2
'nr_band'
:
39
,
'tac'
:
2
,
'plmn'
:
"00101"
},
},
}
...
...
@@ -90,20 +124,6 @@ enb_param_dict = {
'10.0.0.1'
:
{
'mme_addr'
:
'10.0.0.1'
},
'2001:db8::1'
:
{
'mme_addr'
:
'2001:db8::1'
},
},
'ncell_list'
:
{
'ORS1'
:
{
'dl_earfcn'
:
40000
,
'pci'
:
1
,
'cell_id'
:
'0x0000001'
,
'tac'
:
1
},
'ORS2'
:
{
'dl_earfcn'
:
50000
,
'pci'
:
2
,
'cell_id'
:
'0x0000001'
,
'tac'
:
2
},
},
'xlog_forwarding_enabled'
:
False
,
}
gnb_param_dict
=
{
...
...
@@ -129,26 +149,6 @@ gnb_param_dict = {
'xn_addr'
:
'2001:db8::2'
,
},
},
'ncell_list'
:
{
'ORS1'
:
{
'dl_nr_arfcn'
:
403500
,
'ssb_nr_arfcn'
:
403500
,
'pci'
:
1
,
'nr_cell_id'
:
'0x0000001'
,
'gnb_id_bits'
:
28
,
'nr_band'
:
34
,
'tac'
:
1
},
'ORS2'
:
{
'dl_nr_arfcn'
:
519000
,
'ssb_nr_arfcn'
:
519000
,
'pci'
:
2
,
'nr_cell_id'
:
'0x0000002'
,
'gnb_id_bits'
:
30
,
'nr_band'
:
38
,
'tac'
:
2
},
},
'xlog_forwarding_enabled'
:
False
,
}
gnb_param_dict1
=
{
...
...
@@ -205,14 +205,30 @@ class TestENBParameters(ORSTestCase):
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'
])
for
k
in
param_dict
[
'ncell_list'
]:
if
'dl_earfcn'
in
p
:
if
p
[
'dl_earfcn'
]
==
param_dict
[
'ncell_list'
][
k
].
get
(
'dl_earfcn'
,
0
):
break
elif
'dl_nr_arfcn'
in
p
:
if
p
[
'dl_nr_arfcn'
]
==
param_dict
[
'ncell_list'
][
k
].
get
(
'dl_nr_arfcn'
,
0
):
break
conf_ncell
=
param_dict
[
'ncell_list'
][
k
]
if
'dl_earfcn'
in
p
:
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'
])
self
.
assertEqual
(
p
[
'plmn'
],
conf_ncell
[
'plmn'
])
elif
'dl_nr_arfcn'
in
p
:
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'
])
# assumes nr_band is TDD
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'
])
self
.
assertEqual
(
p
[
'plmn'
],
conf_ncell
[
'plmn'
])
class
TestGNBParameters1
(
ORSTestCase
):
...
...
@@ -243,20 +259,35 @@ class TestGNBParameters1(ORSTestCase):
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'
])
# assumes nr_band is TDD
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'
])
for
k
in
param_dict
[
'ncell_list'
]:
if
'dl_earfcn'
in
p
:
if
p
[
'dl_earfcn'
]
==
param_dict
[
'ncell_list'
][
k
].
get
(
'dl_earfcn'
,
0
):
break
elif
'dl_nr_arfcn'
in
p
:
if
p
[
'dl_nr_arfcn'
]
==
param_dict
[
'ncell_list'
][
k
].
get
(
'dl_nr_arfcn'
,
0
):
break
conf_ncell
=
param_dict
[
'ncell_list'
][
k
]
if
'dl_earfcn'
in
p
:
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'
])
self
.
assertEqual
(
p
[
'plmn'
],
conf_ncell
[
'plmn'
])
elif
'dl_nr_arfcn'
in
p
:
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'
])
# assumes nr_band is TDD
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'
])
self
.
assertEqual
(
p
[
'plmn'
],
conf_ncell
[
'plmn'
])
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
)
...
...
@@ -346,7 +377,11 @@ class TestGNBMonitorGadgetUrl(ORSTestCase):
class
TestCoreNetworkMonitorGadgetUrl
(
ORSTestCase
):
@
classmethod
def
getInstanceParameterDict
(
cls
):
return
{
'_'
:
json
.
dumps
({
'testing'
:
True
,
'slave-list'
:
[]})}
return
{
'_'
:
json
.
dumps
({
'testing'
:
True
,
'lte_mock'
:
True
,
'slave-list'
:
[]
})}
@
classmethod
def
getInstanceSoftwareType
(
cls
):
...
...
@@ -391,7 +426,11 @@ class TestSimCard(ORSTestCase):
cls
.
requestSlaveInstanceWithId
(
i
)
@
classmethod
def
getInstanceParameterDict
(
cls
):
return
{
'_'
:
json
.
dumps
({
'testing'
:
True
,
'fixed_ips'
:
cls
.
fixed_ips
})}
return
{
'_'
:
json
.
dumps
({
'testing'
:
True
,
'lte_mock'
:
True
,
'fixed_ips'
:
cls
.
fixed_ips
})}
@
classmethod
def
getInstanceSoftwareType
(
cls
):
return
"core-network"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment