Commit 5d0ba337 authored by Joanne Hugé's avatar Joanne Hugé

Update Release Candidate

parents e5c1e753 e705aae2
......@@ -11,8 +11,8 @@ parts =
[nghttp2]
recipe = slapos.recipe.cmmi
shared = true
url = https://github.com/nghttp2/nghttp2/releases/download/v1.57.0/nghttp2-1.57.0.tar.xz
md5sum = 1525d4966622500f119017dc057c76c8
url = https://github.com/nghttp2/nghttp2/releases/download/v1.62.1/nghttp2-1.62.1.tar.bz2
md5sum = cc2f311e5affee2e78005946e0875fc3
pre-configure =
autoreconf -fisv -I ${libtool:location}/share/aclocal -I ${pkgconfig:location}/share/aclocal
automake
......
......@@ -14,8 +14,8 @@ class WebsocketTestClass(e2e.EndToEndTestCase):
cls.sim_instance_name = time.strftime('e2e-cb003-sim-%Y-%B-%d-%H:%M:%S')
cls.ue_instance_name = time.strftime('e2e-sb005-ue-%Y-%B-%d-%H:%M:%S')
cls.product = "/opt/e2e/slapos/software/ors-amarisoft/software-fdd-lopcomm.cfg"
cls.ue_product = "/opt/e2e/slapos/software/ors-amarisoft/software-fdd-lopcomm.cfg"
cls.product = "/opt/e2e/slapos/software/simpleran/software-fdd-lopcomm.cfg"
cls.ue_product = "/opt/e2e/slapos/software/simpleran/software-fdd-lopcomm.cfg"
# Component GUIDs and configurations
cls.comp_enb ="COMP-3920"
......
......@@ -14,7 +14,7 @@ class WebsocketTestClass(e2e.EndToEndTestCase):
cls.sim_instance_name = time.strftime('e2e-ors84-sim-%Y-%B-%d-%H:%M:%S')
cls.ue_instance_name = time.strftime('e2e-simbox005-ue-%Y-%B-%d-%H:%M:%S')
cls.product = cls.product.get('ors-tdd')
cls.ue_product = "/opt/e2e/slapos/software/ors-amarisoft/software-fdd-lopcomm.cfg"
cls.ue_product = "/opt/e2e/slapos/software/simpleran/software-fdd-lopcomm.cfg"
# Component GUIDs and configurations
cls.comp_enb = "COMP-4057"
......
......@@ -19,4 +19,4 @@ md5sum = 0d6db8da45bbdf311f9c6a2f916045a2
[template-default]
filename = instance-default.cfg.in
md5sum = 452599c3067904a9decb8c5dba55eb46
md5sum = 339a47644377509a754c9ead038728a6
......@@ -11,7 +11,7 @@ parts =
monitor-base
port-listening-promise
galene-service
{% if slapparameter_dict.get('dns_sr_url', '') %}
{% if slapparameter_dict.get('request_dns', '') %}
request-dns-entry
{% endif %}
......@@ -27,7 +27,7 @@ recipe = slapos.cookbook:publish
url = https://[$${galene-wrapper:ip}]:$${galene-wrapper:port}
admin-user = $${admin-password:username}
admin-password = $${admin-password:passwd}
{% if slapparameter_dict.get('dns_sr_url', '') %}
{% if slapparameter_dict.get('request_dns', '') %}
domain-url = https://$${request-dns-entry:connection-domain}:$${galene-wrapper:port}
{% endif %}
......@@ -131,11 +131,11 @@ name = galene-port-listening.py
config-host = $${slap-configuration:ipv6-random}
config-port = 8443
{% if slapparameter_dict.get('dns_sr_url', '') %}
{% if slapparameter_dict.get('request_dns', '') %}
[request-dns-entry]
name = dns-galene-entry
recipe = slapos.cookbook:request.serialised
software-url = {{ slapparameter_dict['dns_sr_url'] }}
software-url = automated_local_dns
software-type = core-network
server-url = {{ slap_connection['server-url'] }}
computer-id = {{ slap_connection['computer-id'] }}
......
......@@ -15,11 +15,11 @@
"type": "boolean",
"default": true
},
"dns_sr_url": {
"default": "",
"title": "DNS SR URL",
"description": "URL of the SR running the DNS server",
"type": "string"
"request_dns": {
"title": "Request DNS",
"description": "Request local DNS to a core network running on the same node",
"type": "boolean",
"default": true
}
}
}
......@@ -466,7 +466,7 @@
"const": [
"https://shacache.nxdcdn.com/02257c3ec27e45d9f022c181a69b59da67e5c72871cdb4f9a69db323a1fad58093f2e69702d29aa98f5f65e920e0b970d816475a5a936e1f3bf33832257b7e92#b710c178eb434d79ce40ce703d30a5f0"
],
"title": "Debian Bookworm 11 netinst x86_64"
"title": "Debian Bullseye 11 netinst x86_64"
},
{
"const": [
......
......@@ -332,7 +332,7 @@
"const": [
"https://shacache.nxdcdn.com/02257c3ec27e45d9f022c181a69b59da67e5c72871cdb4f9a69db323a1fad58093f2e69702d29aa98f5f65e920e0b970d816475a5a936e1f3bf33832257b7e92#b710c178eb434d79ce40ce703d30a5f0"
],
"title": "Debian Bookworm 11 netinst x86_64"
"title": "Debian Bullseye 11 netinst x86_64"
},
{
"const": [
......
......@@ -19,7 +19,7 @@ md5sum = 403a4a362b2ffec05f8d0b591bab92fa
[template-default]
_update_hash_filename_ = instance-default.cfg.in
md5sum = 89a7224c3dd9356bf262100816b67f73
md5sum = 73c1fe98a12465369450cb8f3340881b
[dovecot.jinja2.conf]
_update_hash_filename_ = dovecot.jinja2.conf
......
......@@ -3,11 +3,11 @@
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Input Parameters",
"properties": {
"dns_sr_url": {
"default": "",
"title": "DNS SR URL",
"description": "URL of the SR running the DNS server",
"type": "string"
"request_dns": {
"title": "Request DNS",
"description": "Request local DNS to a core network running on the same node",
"type": "boolean",
"default": true
}
}
}
......@@ -195,7 +195,7 @@ recipe = slapos.cookbook:publish
imap-port = 10143
smtp-port = 10025
imap-smtp-ipv6 = ${slap-configuration:ipv6-random}
{% if slapparameter_dict.get('dns_sr_url', '') %}
{% if slapparameter_dict.get('request_dns', '') %}
domain = ${request-dns-entry:connection-domain}
{% endif %}
......@@ -216,7 +216,7 @@ config-port = 10025
[request-dns-entry]
name = dns-mail-entry
recipe = slapos.cookbook:request.serialised
software-url = {{ slapparameter_dict['dns_sr_url'] }}
software-url = automated_local_dns
software-type = core-network
server-url = {{ slap_connection['server-url'] }}
computer-id = {{ slap_connection['computer-id'] }}
......@@ -302,7 +302,7 @@ parts =
imap-listen-promise
smtp-listen-promise
{{ part_list | join('\n ') }}
{% if slapparameter_dict.get('dns_sr_url', '') %}
{% if slapparameter_dict.get('request_dns', '') %}
request-dns-entry
{% endif %}
......
Tests for ors-amarisoft software release
......@@ -16,15 +16,15 @@
[template]
filename = instance.cfg
md5sum = 711d90973a5cfb2f61d3a3a53c07c64c
md5sum = f1b9ae02222c020c89d1a3fa75475826
[template-ors]
filename = instance-ors.cfg
md5sum = 1e7d200bfbbbae26e56585017177aaee
md5sum = 8c2abee8eb0a538ad8ae1a84e140af69
[slaplte.jinja2]
_update_hash_filename_ = slaplte.jinja2
md5sum = 27c49897c9a3e4c260105534bed0132d
md5sum = 8d6eb90fc1191c3a1b24200df2ebf4fa
[ru_amarisoft-stats.jinja2.py]
_update_hash_filename_ = ru/amarisoft-stats.jinja2.py
......@@ -60,19 +60,23 @@ md5sum = 52da9fe3a569199e35ad89ae1a44c30e
[template-enb]
_update_hash_filename_ = instance-enb.jinja2.cfg
md5sum = 140cce72eb04768abbe87ea4982f36bd
md5sum = bda6ff7bc76cf73e3bd55aca21134a3a
[template-ors-enb]
_update_hash_filename_ = instance-ors-enb.jinja2.cfg
md5sum = 601d6237059fa665d3f3ffb6a78ad9ca
md5sum = 585457493ce5302ba1f1073b8a3b877c
[template-ors-ue]
_update_hash_filename_ = instance-ors-ue.jinja2.cfg
md5sum = f4389a92fb111447e7976e452db78607
[template-core-network]
_update_hash_filename_ = instance-core-network.jinja2.cfg
md5sum = 8e3f5a1a742a6934a61d6a3a282f1293
md5sum = dab992c02a363e00cdc86f102a7ae489
[template-ue]
_update_hash_filename_ = instance-ue.jinja2.cfg
md5sum = 812a43458c21f7d0cdb2141515a236ae
md5sum = eb4c1c0e654922ded618991e5f3c0f8f
[template-obsolete]
_update_hash_filename_ = instance-obsolete.jinja2.cfg
......@@ -80,11 +84,11 @@ md5sum = c5f581ba01654b2aec46000abf8d0e35
[ue_db.jinja2.cfg]
filename = config/ue_db.jinja2.cfg
md5sum = 3b901e8733e6afff8940c6c318da4493
md5sum = dd50b4e4780830ddbde28b84af118f18
[enb.jinja2.cfg]
filename = config/enb.jinja2.cfg
md5sum = 1b8dc68206485299c08ab0e1544773f6
md5sum = 2c49e14af6869387880d5e8e1c0ede64
[drb_lte.jinja2.cfg]
filename = config/drb_lte.jinja2.cfg
......@@ -104,7 +108,7 @@ md5sum = 9dbd93036c15c87c6de74b88b34062b6
[mme.jinja2.cfg]
filename = config/mme.jinja2.cfg
md5sum = 4628509e89747cf30e85ce2cb3a0aebd
md5sum = b86f0e7a0d890771d56aee22838d6487
[dnsmasq-core-network.jinja2.cfg]
filename = config/dnsmasq-core-network.jinja2.cfg
......@@ -120,7 +124,7 @@ md5sum = f07c85916bcb7e4002c8edc3d087c1be
[ue.jinja2.cfg]
filename = config/ue.jinja2.cfg
md5sum = 62291a11fd36a42464901cdc81338687
md5sum = 4b0f08b2d8efa506d6165f8b4e0d9578
[software.cfg.html]
_update_hash_filename_ = gadget/software.cfg.html
......@@ -129,3 +133,11 @@ md5sum = 61a2f783fbf683a34aed3d13e00baca2
[promise.gadget.js]
_update_hash_filename_ = gadget/promise.gadget.js
md5sum = 330f5f07806f1da11cd05bb8e4b52e55
[ue-ifup]
_update_hash_filename_ = config/ue-ifup
md5sum = f02fbfd31ba89cf243e2752adcae28d9
[frequency_outofbounds_promise]
_update_hash_filename_ = promise/check_frequency_outofbounds.py
md5sum = 7c83eab2df4f5a5d519e3eb16e4077a3
Changelog
=========
Version 1.0.371 (2024-10-09)
-------------
* rename ors-amarisoft to simpleran
## UE simulator:
* add UE mode for ORS (experimental)
## eNB / gNB changes:
* add compatibility with our KPI calculation and storage platform
* support external MBMSGW
* display current frequency and band
* add promise testing if frequency is out of bounds (ORS only)
* fix eNB configuration for 1.4MHz bandwidth
* change default RX gain to 25
* add useful information in eNB / gNB logs: host ID, FPGA version and kernel version
* keep old eNB / gNB radio logs
## Core Network changes:
* support external HSS (S6), tested only for LTE
* add multicast and broadcast
* display the list of IMSI in the UE database
Version 1.0.361 (2024-05-29)
-------------
......
......@@ -143,7 +143,7 @@
log_filename: "{{ directory['log'] }}/enb.log",
{# instantiate radio units #}
{{ slaplte.ru_config(iru_dict, slapparameter_dict) }}
{{ slaplte.ru_config(iru_dict, slapparameter_dict, True) }}
{%- if slapparameter_dict.get('websocket_password', '') %}
com_addr: "[{{ gtp_addr_v6 }}]:{{ slapparameter_dict.com_ws_port }}",
......@@ -155,12 +155,19 @@
com_addr: "{{ slapparameter_dict.com_addr }}:{{ slapparameter_dict.com_ws_port }}",
{%- endif %}
{%- if slapparameter_dict.get('mbmsgw_addr', '') %}
mbmsgw_addr: "{{ slapparameter_dict.mbmsgw_addr }}",
{%- endif %}
{% if do_lte %}
// LTE core network
mme_list: [
{%- for _, mme in slapparameter_dict.mme_list |dictsort %}
{
mme_addr: "{{ mme['mme_addr'] }}",
{%- if mme.get('s1ap_bind_addr', '') %}
s1ap_bind_addr: "{{ mme['s1ap_bind_addr'] }}",
{%- endif %}
},
{%- endfor %}
],
......@@ -172,6 +179,9 @@
{%- for _, amf in slapparameter_dict.amf_list |dictsort %}
{
amf_addr: "{{ amf['amf_addr'] }}",
{%- if amf.get('ngap_bind_addr', '') %}
ngap_bind_addr: "{{ amf['ngap_bind_addr'] }}",
{%- endif %}
},
{%- endfor %}
],
......@@ -306,7 +316,7 @@
{%- set n_rb_dl = J(jlte_n_rb_dl(cell.bandwidth)) %}
n_rb_dl: {{ n_rb_dl }},
si_coderate: {{ 0.30 if n_rb_dl == 6 else 0.20 }},
si_coderate: {{ 0.60 if n_rb_dl == 6 else 0.20 }},
pdsch_dedicated: {
p_a: {{ {4: -6, 2: -3}.get(ru.n_antenna_dl, 0) }},
......@@ -314,7 +324,7 @@
},
pdcch_format: {{ 1 if n_rb_dl == 6 else 2 }},
prach_config_index: {{ 15 if n_rb_dl == 6 else 4 }},
prach_config_index: {{ 0 if n_rb_dl == 6 else 4 }},
initial_cqi: {{ 5 if n_rb_dl == 6 else 3 }},
pucch_dedicated: {
......@@ -342,7 +352,7 @@
srs_dedicated: {
{%- if n_rb_dl == 6 %}
srs_bandwidth_config: 7,
srs_bandwidth: 1,
srs_bandwidth: 3,
{%- elif n_rb_dl == 15 %}
srs_bandwidth_config: 6,
srs_bandwidth: 1,
......
......@@ -59,7 +59,12 @@
nr_support: true,
eps_5gs_interworking: "with_n26",
{%- set eps_5gs_interworking =
{'With N26': "with_n26",
'Without N26': "without_n26",
'None': "none"}
[slapparameter_dict.get('eps_5gs_interworking', 'With N26')] %}
eps_5gs_interworking: "{{ eps_5gs_interworking }}",
fifteen_bearers: false,
......@@ -128,6 +133,23 @@
ue_to_ue_forwarding: false,
nas_cipher_algo_pref: [ ],
nas_integ_algo_pref: [ 2, 1 ],
ue_db_filename: "{{ directory['var'] }}/lte_ue.db",
{%- if slapparameter_dict.get('hss_addr', '') %}
ue_db: [],
s6: {
server_addr: "{{ slapparameter_dict.get('hss_addr', '') }}",
{%- if slapparameter_dict.get('hss_bind_addr', '') %}
bind_addr: "{{ slapparameter_dict.get('hss_bind_addr', '') }}",
{%- endif %}
{%- if slapparameter_dict.get('s6_origin_realm', '') %}
origin_realm: "{{ slapparameter_dict.get('s6_origin_realm', '') }}",
{%- endif %}
{%- if slapparameter_dict.get('s6_origin_host', '') %}
origin_host: "{{ slapparameter_dict.get('s6_origin_host', '') }}",
{%- endif %}
}
{%- else %}
include "{{ slap_configuration['ue_db_path'] }}",
ue_db_filename: "{{ directory['var'] }}/lte_ue.db"
{%- endif %}
}
#!/bin/bash
ue_id="$1"
pdn_id="$2"
ifname="$3"
ipv4_addr="$4"
ipv4_dns="$5"
ipv6_local_addr="$6"
ipv6_dns="$7"
param="$8"
old_link_local=""
shift; shift; shift; shift; shift; shift; shift; shift;
while [ "$1" != "" ] ; do
case "$1" in
--mtu)
mtu="$2"
shift
;;
*)
echo "Bad parameter: $1" >&2
exit 1
;;
esac
shift
done
if [ "$pdn_id" != "0" ] ; then
echo "We should have only PDN 0, exiting..."
exit 1
fi
echo "Configure $ue_id($param) on pdn $pdn_id, tun=$ifname, ip=$ipv4_addr, dns=$ipv4_dns, ip6=$ipv6_local_addr, ip6_dns=$ipv6_dns"
if [ "$ipv4_dns" != "" ] || [ "$ipv6_dns" != "" ] ; then
if [ "$ipv4_dns" != "" ] ; then
echo "nameserver $ipv4_dns" >> /etc/resolv.conf
fi
if [ "$ipv6_dns" != "" ] ; then
echo "nameserver $ipv6_dns" >> /etc/resolv.conf
fi
fi
if [ "$ipv6_local_addr" != "" ] ; then
echo '0' > /proc/sys/net/ipv6/conf/$ifname/disable_ipv6
echo '1' > /proc/sys/net/ipv6/conf/$ifname/accept_ra
echo '1' > /proc/sys/net/ipv6/conf/$ifname/router_solicitation_delay
echo '1' > /proc/sys/net/ipv6/conf/$ifname/autoconf
else
echo '1' > /proc/sys/net/ipv6/conf/$ifname/disable_ipv6
fi
ifconfig $ifname up
if [ "$ipv4_addr" != "" ] ; then
ifconfig $ifname $ipv4_addr/24
if [ "$mtu" != "" ] ; then
ifconfig $ifname mtu $mtu
fi
fi
if [ "$ipv6_local_addr" != "" ] ; then
old_link_local=`ip addr show dev $ifname | sed -e's/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d'`
if [ "$old_link_local" != "" ] ; then
ifconfig $ifname inet6 del $old_link_local/64
fi
ifconfig $ifname inet6 add $ipv6_local_addr/64
fi
if [ "$ipv4_addr" != "" -a "$ipv6_local_addr" != "" ] ; then
echo "MAC_ADDR="$(ip link show dev $ifname | grep -oP "ether \K[\d:a-f]+")
fi
......@@ -20,12 +20,17 @@
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",
{%- if not ors %}
rue_bind_addr: "{{ pub_info['rue_bind_addr'] }}",
com_addr: "{{ pub_info['com_addr'] }}",
{%- endif %}
{# instantiate radio units #}
{{ slaplte.ru_config(iru_dict, slapparameter_dict) }}
{%- if ors %}
{{ slaplte.ru_config(iru_dict, slapparameter_dict, False) }}
{%- else %}
{{ slaplte.ru_config(iru_dict, slapparameter_dict, True) }}
{%- endif %}
cell_groups: [{
// LTE cells
......@@ -102,7 +107,9 @@
impi: "{{ ue.impi }}",
imsi: "{{ ue.imsi }}",
K: "{{ ue.k }}",
{%- if ue.get('rue_addr', False) %}
rue_addr: "{{ ue.rue_addr }}",
{%- endif %}
{%- if ue.ue_type == 'lte' %}
as_release: 13,
ue_category: 13,
......@@ -112,7 +119,11 @@
{%- else %}
{%- do bug('unreachable') %}
{%- endif %}
tun_setup_script: "ue-ifup",
{%- if ors %}
tun_setup_script: "{{ ue_ifup }}",
{%- else %}
tun_setup_script: "ue_ifup",
{%- endif %}
apn: "internet",
},
{%- endfor %}
......
......@@ -14,11 +14,34 @@ ue_db: [
K: "{{ s.get('k', '') }}",
impu: "{{ s.get('impu', '') }}",
impi: "{{ s.get('impi', '') }}",
{%- if "ip" in s %}
{%- if "ip" in s or s.get('enable_multicast', False) or s.get('enable_ipv6_multicast', False) or s.get('enable_broadcast') or s.get('route_list', False) %}
pdn_list:[{
access_point_name: "internet",
default: true,
{%- if "ip" in s %}
ipv4_addr: "{{ s['ip'] }}"
{%- endif %}
{%- if s.get('enable_multicast', False) %}
multicast: true,
{%- endif %}
{%- if s.get('enable_ipv6_multicast', False) %}
ipv6_multicast: true,
{%- endif %}
{%- if s.get('enable_broadcast', False) %}
broadcast: true,
{%- endif %}
{%- if s.get('route_list', False) %}
routes: [
{%- for _, route in s.route_list |dictsort %}
[
{
ipv6_remote_addr_prefix: "{{ route['ipv6_remote_addr_prefix'] }}",
prefix_len: {{ route['prefix_len'] }},
}
],
{%- endfor -%}
],
{%- endif %}
}]
{%- endif %}
}
......
......@@ -50,6 +50,37 @@
"title": "Fixed IP for the UE",
"description": "Set to true to force a static IPv4 for each UE. If true, the number of UE is limited.",
"type": "boolean"
},
"eps_5gs_interworking": {
"title": "EPS 5GS Interworking",
"type": "string",
"description": "Defines whether inter RAT mobility between EPS and 5GS is supported or not, and whether N26 interface is supported or not. Note that interworking with N26 is required to perform handover between EPS and 5GS.",
"enum": [
"None",
"With N26",
"Without N26"
],
"default": "With N26"
},
"hss_addr": {
"title": "HSS Address",
"description": "IP address and optional port of the HSS used for S6a interface. The default port is 3868.",
"type": "string"
},
"hss_bind_addr": {
"title": "HSS Bind Address",
"description": "IP address and optional port on which the S6a SCTP connection is bound. The default address is the same as the S1AP SCTP connection.",
"type": "string"
},
"s6_origin_realm": {
"title": "S6 Origin Realm",
"description": "Defines the string sent in the Origin-Realm AVP for S6 messages. Default is set to mnc<MNC>.mcc<MCC>.3gppnetwork.org.",
"type": "string"
},
"s6_origin_host": {
"title": "S6 Origin Host",
"description": "Defines the string sent in the Origin-Host AVP for S6 messages. Default is set to epc.mnc<MNC>.mcc<MCC>.3gppnetwork.org.",
"type": "string"
}
}
}
......@@ -267,11 +267,7 @@ context =
[mme-config]
<= config-base
{% if slapparameter_dict.get("mme_config_link", None) %}
url = ${mme-config-dl:target}
{% else %}
url = {{ mme_template }}
{% endif %}
output = ${directory:etc}/mme.cfg
extra-context =
raw support_ims {{ support_ims }}
......@@ -316,6 +312,12 @@ monitor-title = {{ slapparameter_dict['name'] | string }}
password = {{ slapparameter_dict['monitor-password'] | string }}
{% endif %}
{% set imsi_list = [] -%}
{%- for slave in sim_slave_instance_list %}
{%- set slave_parameters = json_module.loads(slave['_']) %}
{%- do imsi_list.append(slave_parameters.imsi) %}
{%- endfor %}
[publish-connection-information]
<= monitor-publish
recipe = slapos.cookbook:publish.serialised
......@@ -329,6 +331,7 @@ core-network-ipv4 = {{ lan_ipv4 }}
amarisoft-version = {{ lte_version }}
license-expiration = {{ lte_expiration }}
monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html
sim-list = {{ imsi_list | join(', ') }}
[macro.promise]
<= monitor-promise-base
......
......@@ -20,6 +20,11 @@
"type": "string",
"default": "127.0.1.1"
},
"mbmsgw_addr": {
"title": "SGW Address",
"description": "Set the IP address (and optional port) of the MBMS Gateway for the M2 connection. The default port is 36443.",
"type": "string"
},
"mme_list": {
"title": "MME list",
"description": "List of MME to which the eNodeB is connected. (must be set if there are LTE cells)",
......@@ -30,6 +35,11 @@
"title": "MME Address",
"description": "IP address (and optional port) of S1AP SCTP connection to the MME. The default port is 36412.",
"type": "string"
},
"s1ap_bind_addr": {
"title": "S1AP Bind Address",
"description": "Optional String. IP address and optional port on which the S1AP SCTP connection is bound.",
"type": "string"
}
},
"type": "object"
......@@ -87,6 +97,11 @@
"title": "AMF Address",
"description": "IP address (and optional port) of NGAP SCTP connection to the AMF. The default port is 38412.",
"type": "string"
},
"ngap_bind_addr": {
"title": "NGAP Bind Address",
"description": "Optional string. IP address and optional port on which the NGAP SCTP connection is bound.",
"type": "string"
}
},
"type": "object"
......@@ -197,19 +212,27 @@
"type": "number",
"default": 0
},
"wendelin_telecom_software_release_url": {
"title": "Wendelin Telecom Software Release URL",
"description": "URL of the Wendelin Telecom Software Release to use to request a shared instance",
"type": "string",
"default": "wendelin-telecom-enb-shared-instance"
},
"xlog_fluentbit_forward_host": {
"title": "Fluentbit Xlog forwarding address",
"description": "Address of remote Fluentd or Fluentbit server to which Fluentbit should forward Xlog data",
"type": "string"
"type": "string",
"default": "fluentd.rapid.space"
},
"xlog_fluentbit_forward_port": {
"title": "Fluentbit Xlog forwarding port",
"description": "(Optional) Port of remote Fluentd or Fluentbit server to which Fluentbit should forward Xlog data",
"type": "string"
"description": "Port of remote Fluentd or Fluentbit server to which Fluentbit should forward Xlog data",
"type": "integer",
"default": 24224
},
"xlog_fluentbit_forward_shared_key": {
"title": "Fluentbit Xlog forwarding shared key",
"description": "Secret Key shared with remote Fluentd or Fluentbit server for authentication when forwarding Xlog data",
"description": "Secret key shared with remote Fluentd or Fluentbit server for authentication when forwarding Xlog data",
"type": "string"
}
}
......
......@@ -8,25 +8,30 @@
'use_ipv4': False,
'gnb_id_bits': 28,
'nssai': {'1': {'sst': 1}},
'wendelin_telecom_software_release_url': 'wendelin-telecom-enb-shared-instance',
'xlog_fluentbit_forward_host': 'fluentd.rapid.space',
'xlog_fluentbit_forward_port': 24224,
} %}
{%- set gtp_addr_lo = '127.0.1.1' %}
{%- for k,v in enb_defaults|dictsort %}
{%- do slapparameter_dict.setdefault(k, v) %}
{%- endfor %}
{%- set B = xbuildout.encode %}
[buildout]
extra-parts =
parts =
directory
enb-config
enb-service
xamari-xlog-service
{% if slapparameter_dict.get('xlog_fluentbit_forward_host') %}
xlog-fluentbit-service
{% endif %}
request-wendelin-telecom-shared
check-baseband-latency.py
monitor-base
publish-connection-information
${:extra-parts}
extends = {{ monitor_template }}
......@@ -82,28 +87,39 @@ promise = ${:etc}/promise
log = ${:var}/log
xlog-fluentbit = ${:var}/xlog-fluentbit
{% if slapparameter_dict.get("enb_config_link", None) %}
[enb-config-dl]
recipe = slapos.recipe.build:download
url = {{ slapparameter_dict.get("enb_config_link") }}
version = {{ slapparameter_dict.get("enb_config_version") }}
offline = false
{% endif %}
[enb-sh-wrapper]
recipe = slapos.recipe.template
output = ${directory:bin}/${:_buildout_section_name_}
enb-log = ${directory:log}/enb-output.log
enb-info-log = ${directory:log}/enb-info.log
enb-info-archive-log = ${directory:log}/enb-info.log
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) %}
sudo -n /opt/amarisoft/rm-tmp-lte;
sudo -n /opt/amarisoft/init-sdr;
sudo -n /opt/amarisoft/init-enb;
(echo && echo && date "+[%Y/%m/%d %T.%N %Z] Starting eNB software..." && echo) >> ${:enb-log};
tail -c 1M ${:enb-log} > ${:enb-log}.tmp;
mv ${:enb-log}.tmp ${:enb-log};
{{ enb }}/lteenb ${directory:etc}/enb.cfg >> ${:enb-log} 2>> ${:enb-log};
# Amarisoft init scripts
sudo -n /opt/amarisoft/rm-tmp-lte
sudo -n /opt/amarisoft/init-sdr
sudo -n /opt/amarisoft/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 "System info: $(uname -a)" >> ${:enb-info-log}
({{ sdr }}/sdr_util version && echo) >> ${:enb-info-log}
# Keep the 50 latest enb radio log
stat ${:enb-start-date} && mv ${:enb-radio-log} ${directory:log}/enb-$(cat ${:enb-start-date}).log
rm -f $(ls -1t ${directory:log}/enb-2* | tail -n+50)
rm -f $(ls -1t ${directory:log}/enb-info-2* | tail -n+50)
date +"%Y-%m-%d-%T" > ${:enb-start-date}
# Trim enb info log to 500k and keep a 100M archive of enb info log
head -c -500k ${:enb-info-log} >> ${:enb-info-archive-log}
tail -c 500k ${:enb-info-log} > ${:enb-info-log}.tmp
mv ${:enb-info-log}.tmp ${:enb-info-log}
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 %}
[enb-service]
......@@ -149,12 +165,11 @@ wrapper-path = ${directory:service}/${:_buildout_section_name_}
command-line = ${xamari-xlog-script:output}
hash-files = ${:command-line}
{% if slapparameter_dict.get('xlog_fluentbit_forward_host') %}
[xlog-fluentbit-tag]
recipe = slapos.recipe.build
computer = ${slap-connection:computer-id}
enb-id = {{ slapparameter_dict.get("enb_id", "") }}
gnb-id = {{ slapparameter_dict.get("gnb_id", "") }}
enb-id = {{ slapparameter_dict.get("enb_id") }}
gnb-id = {{ slapparameter_dict.get("gnb_id") }}
init =
import socket
......@@ -174,10 +189,10 @@ init =
recipe = slapos.recipe.template
output = ${directory:etc}/${:_buildout_section_name_}.cfg
logfile = ${xamari-xlog-script:logfile}
forward-host = {{ slapparameter_dict.get('xlog_fluentbit_forward_host', '') }}
forward-port = {{ slapparameter_dict.get('xlog_fluentbit_forward_port', '') }}
forward-host = {{ slapparameter_dict.xlog_fluentbit_forward_host }}
forward-port = {{ slapparameter_dict.xlog_fluentbit_forward_port }}
forward-shared-key = {{ slapparameter_dict.get('xlog_fluentbit_forward_shared_key', '') }}
forward-self-hostname = {{ comp_id['comp-id'] }}
forward-self-hostname = {{ B(comp_id['comp-id']) }}
inline =
[SERVICE]
flush 5
......@@ -191,9 +206,7 @@ inline =
name forward
match *
Host ${:forward-host}
{%- if slapparameter_dict.get('xlog_fluentbit_forward_port') %}
Port ${:forward-port}
{%- endif %}
{%- if slapparameter_dict.get('xlog_fluentbit_forward_shared_key') %}
Shared_Key ${:forward-shared-key}
{%- endif %}
......@@ -208,7 +221,14 @@ fluentbit-config = ${xlog-fluentbit-config:output}
command-line = ${:fluentbit} -c ${:fluentbit-config}
wrapper-path = ${directory:service}/${:_buildout_section_name_}
hash-files = ${:fluentbit-config}
{% endif %}
[request-wendelin-telecom-shared]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Wendelin Telecom Registration
software-url = {{ slapparameter_dict.wendelin_telecom_software_release_url }}
shared = true
config-fluentbit-tag = ${xlog-fluentbit-tag:xlog-fluentbit-tag}
[config-base]
recipe = slapos.recipe.template:jinja2
......@@ -228,11 +248,7 @@ context =
[enb-config]
<= config-base
{% if slapparameter_dict.get("enb_config_link", None) %}
url = ${enb-config-dl:target}
{% else %}
url = {{ enb_template }}
{% endif %}
output = ${directory:etc}/enb.cfg
import-list =
rawfile slaplte.jinja2 {{ slaplte_template }}
......@@ -263,9 +279,7 @@ ru-list = {{ dumps(rulib.iru_dict.keys() | sort) }}
cell-list = {{ dumps(rulib.icell_dict.keys() | sort) }}
peer-list = {{ dumps(ipeer_dict.keys() | sort) }}
peer-cell-list = {{ dumps(ipeercell_dict.keys() | sort) }}
{%- if slapparameter_dict.get('xlog_fluentbit_forward_host') %}
fluentbit-tag = ${xlog-fluentbit-tag:xlog-fluentbit-tag}
{%- endif %}
[monitor-instance-parameter]
......
......@@ -73,6 +73,9 @@
"$ref": "instance-enb-input-schema.json#/properties/gtp_addr",
"default": "127.0.1.1"
},
"mbmsgw_addr": {
"$ref": "instance-enb-input-schema.json#/properties/mbmsgw_addr"
},
"mme_list": {
"$ref": "instance-enb-input-schema.json#/properties/mme_list",
"default": {
......@@ -196,6 +199,9 @@
"min_rxtx_delay": {
"$ref": "instance-enb-input-schema.json#/properties/min_rxtx_delay"
},
"wendelin_telecom_software_release_url": {
"$ref": "instance-enb-input-schema.json#/properties/wendelin_telecom_software_release_url"
},
"xlog_fluentbit_forward_host": {
"$ref": "instance-enb-input-schema.json#/properties/xlog_fluentbit_forward_host"
},
......
......@@ -199,12 +199,6 @@
are present, replace their generic enb_* counterparts with gnb_* ones #}
{%- if enb_mode == 'gnb' %}
{%- set _ = slapparameter_dict %}
{%- if 'gnb_config_link' in _ %}
{%- do _.update({
'enb_config_link': _.gnb_config_link,
'enb_config_version': _.get('gnb_config_version'),
}) %}
{%- endif %}
{%- if 'gnb_stats_fetch_period' in _ %}
{%- do _.update({'enb_stats_fetch_period': _.gnb_stats_fetch_period}) %}
{%- endif %}
......@@ -236,10 +230,13 @@ current-tx-gain = {{ ors_version['current-tx-gain'] }}
current-rx-gain = {{ ors_version['current-rx-gain'] }}
{%- if enb_mode == 'enb' %}
current-frequency = {{ xearfcn_module.frequency(ors_version['current-earfcn']) }} MHz
current-band = {{ xearfcn_module.band(ors_version['current-earfcn'])[0]["band"] }}
current-earfcn = {{ ors_version['current-earfcn'] }}
{%- elif enb_mode == 'gnb' %}
current-nr-arfcn = {{ ors_version['current-nr-arfcn'] }}
current-frequency = {{ xnrarfcn_module.frequency(ors_version['current-nr-arfcn']) }} MHz
current-nr-band = {{ ors_version['current-nr-band'] }}
current-nr-arfcn = {{ ors_version['current-nr-arfcn'] }}
{%- endif %}
......@@ -254,3 +251,20 @@ init =
del publish['cell-list']
del publish['peer-list']
del publish['peer-cell-list']
# Add custom promise to check if /dev/sdr0 is busy
[frequency-outofbounds-promise]
recipe = slapos.cookbook:promise.plugin
eggs = slapos.core
file = {{ frequency_outofbounds_promise }}
output = ${directory:plugins}/check-frequency-outofbounds.py
{%- if enb_mode == 'enb' %}
config-frequency = {{ xearfcn_module.frequency(ors_version['current-earfcn']) }}
{%- elif enb_mode == 'gnb' %}
config-frequency = {{ xnrarfcn_module.frequency(ors_version['current-nr-arfcn']) }}
{%- endif %}
config-range-rating = {{ ors_version['range'] }}
[buildout]
extra-parts +=
frequency-outofbounds-promise
......@@ -50,6 +50,13 @@
"$ref": "instance-enb-input-schema.json#/properties/gnb_id_bits",
"default": 28
},
"gtp_addr": {
"$ref": "instance-enb-input-schema.json#/properties/gtp_addr",
"default": "127.0.1.1"
},
"mbmsgw_addr": {
"$ref": "instance-enb-input-schema.json#/properties/mbmsgw_addr"
},
"amf_list": {
"$ref": "instance-enb-input-schema.json#/properties/amf_list",
"default": {
......
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"properties": {
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth",
"type": "string",
"enum": [
"1.4 MHz",
"3 MHz",
"5 MHz",
"10 MHz",
"15 MHz",
"20 MHz"
],
"default": "20 MHz"
},
"n_antenna_dl": {
"$ref": "ru/common.json#/properties/n_antenna_dl",
"enum": [
1,
2
],
"default": 2
},
"n_antenna_ul": {
"$ref": "ru/common.json#/properties/n_antenna_ul",
"enum": [
1,
2
],
"default": 2
},
"rf_mode": {
"$ref": "cell/common.json#/properties/rf_mode",
"default": "tdd"
},
"dl_earfcn": {
"$ref": "cell/lte/input-schema.json#/properties/dl_earfcn"
},
"tx_gain": {
"$ref": "ru/common.json#/properties/tx_gain"
},
"rx_gain": {
"$ref": "ru/common.json#/properties/rx_gain"
},
"log_phy_debug": {
"$ref": "instance-enb-input-schema.json#/properties/log_phy_debug"
},
"disable_sdr": {
"default": false,
"title": "Disable SDR",
"description": "Disables radio",
"type": "boolean"
}
}
}
{
"$schema": "http://json-schema.org/draft-04/schema",
"description": "Values returned by ORS UE instantiation (stub)",
"type": "object",
"properties": {}
}
{%- set ors_defaults = {
"bandwidth": "20 MHz",
"n_antenna_dl": 2,
"n_antenna_ul": 1,
"rf_mode": "tdd",
"plmn": "00101",
"disable_sdr": false
} %}
{%- for k,v in ors_defaults|dictsort %}
{%- do slapparameter_dict.setdefault(k, v) %}
{%- endfor %}
{#- make real ru/cell/peer/... shared instances to be rejected in ORS mode #}
{%- set ishared_list = slap_configuration.setdefault('slave-instance-list', []) %}
{%- for ishared in ishared_list %}
{%- set _ = json_module.loads(ishared['_']) %}
{%- if 'ru_type' in _ or 'cell_type' in _ %}
{%- do ishared.update({'_': {'REJECT': 1}|tojson}) %}
{%- endif %}
{%- if 'imsi' in _ %}
{%- do _.update({'ue_type': 'lte'}) %}
{%- endif %}
{%- endfor %}
{#- inject ru+cell synthesized from ORS-specific parameters #}
{%- macro iref(name) %}
{{- '%s.%s' % (slap_configuration['instance-title'], name) -}}
{%- endmacro %}
{%- do ishared_list.append({
'slave_title': iref('RU'),
'slave_reference': False,
'_': {
'ru_type': 'sdr',
'ru_link_type': 'sdr',
'sdr_dev_list': [0],
'n_antenna_dl': slapparameter_dict.n_antenna_dl,
'n_antenna_ul': slapparameter_dict.n_antenna_ul,
'tx_gain': ors_version['current-tx-gain'],
'rx_gain': ors_version['current-rx-gain'],
'txrx_active': 'ACTIVE' if (not slapparameter_dict.disable_sdr) else 'INACTIVE',
} |tojson
})
%}
{%- set cell = {
'cell_type': 'lte',
'dl_earfcn': ors_version['current-earfcn'],
'bandwidth': float(slapparameter_dict.bandwidth.removesuffix(' MHz')),
}
%}
{%- do cell.update({
'cell_kind': 'ue',
'rf_mode': slapparameter_dict.rf_mode,
'ru': { 'ru_type': 'ru_ref',
'ru_ref': iref('RU') }
})
%}
{%- do ishared_list.append({
'slave_title': iref('CELL'),
'slave_reference': False,
'_': cell | tojson
})
%}
# code of generic ue
{% include 'instance-ue-base.jinja2.cfg' %}
# let all templates know we are running in ORS mode
[config-base]
context -=
json ors false
context +=
key ors :ors
raw ue_ifup {{ ue_ifup }}
ors = {{ dumps(ors_version) }}
# add ORS-specific bits to published information
[publish-connection-information]
ors-version = {{ ors_version['ors-version'] }}
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'] }}
current-earfcn = {{ ors_version['current-earfcn'] }}
......@@ -10,7 +10,7 @@ enb-epc = $${:obsolete}
gnb-epc = $${:obsolete}
epc = $${:obsolete}
mme = $${:obsolete}
ue =
ue = dynamic-template-ors-ue:output
[dynamic-template-obsolete]
< = jinja2-template-base
......@@ -30,9 +30,21 @@ filename = instance-enb.cfg
extra-context +=
section ors ors-version
section ors_version ors-version
raw frequency_outofbounds_promise ${frequency_outofbounds_promise:target}
import-list +=
rawfile instance-enb-base.jinja2.cfg ${template-enb:target}
[dynamic-template-ors-ue]
< = dynamic-template-ue
url = ${template-ors-ue:target}
filename = instance-ue.cfg
extra-context +=
section ors ors-version
section ors_version ors-version
raw ue_ifup ${ue-ifup:output}
import-list +=
rawfile instance-ue-base.jinja2.cfg ${template-ue:target}
[ors-version]
recipe = slapos.recipe.build
configuration = $${slap-configuration:configuration}
......
......@@ -58,27 +58,30 @@ service = ${:etc}/service
promise = ${:etc}/promise
log = ${:var}/log
{% if slapparameter_dict.get("ue_config_link", None) %}
[ue-config-dl]
recipe = slapos.recipe.build:download
url = {{ slapparameter_dict.get("ue_config_link") }}
version = {{ slapparameter_dict.get("ue_config_version") }}
offline = false
{% endif %}
[lte-ue-sh-wrapper]
recipe = slapos.recipe.template
output = ${directory:bin}/${:_buildout_section_name_}
ue-log = ${directory:log}/ue-output.log
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;
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};
{%- else %}
{{ ue }}/lteue ${directory:etc}/ue.cfg >> ${:ue-log} 2>> ${:ue-log};
{% endif %}
{%- endif %}
{%- endif %}
### User Equipment (UE)
[lte-ue-service]
......@@ -110,11 +113,7 @@ context =
[lte-ue-config]
<= config-base
{% if slapparameter_dict.get("ue_config_link", None) %}
url = ${ue-config-dl:target}
{% else %}
url = {{ ue_template }}
{% endif %}
output = ${directory:etc}/ue.cfg
import-list =
rawfile slaplte.jinja2 {{ slaplte_template }}
......
......@@ -127,7 +127,7 @@ title = $${slap-configuration:root-instance-title}
init =
import socket
options['hostname'] = socket.gethostname()
comp_id = '__'.join(options[x] for x in ('hostname', 'computer', 'title'))
comp_id = '_'.join(options[x] for x in ('hostname', 'computer', 'title'))
options['comp-id'] = comp_id
[switch-softwaretype]
......
import os
import errno
from zope.interface import implementer
from slapos.grid.promise import interface
from slapos.grid.promise.generic import GenericPromise
@implementer(interface.IPromise)
class RunPromise(GenericPromise):
def __init__(self, config):
"""
Called when initialising the promise before testing.
Sets the configuration and the periodicity.
"""
super(RunPromise, self).__init__(config)
self.setPeriodicity(minute=1)
def sense(self):
"""
Called every time the promise is tested.
Signals a positive or negative result.
In this case, check whether the file exists.
"""
frequency = self.getConfig('frequency')
range_rating = self.getConfig('range-rating')
try:
min_frequency = int(range_rating.split('MHz')[0].strip())
max_frequency = int(range_rating.split('-')[1].split('MHz')[0].strip())
except (IndexError, ValueError) as e:
self.logger.info("Range rating not available, skipping the promise")
return
try:
frequency = int(float(frequency))
except ValueError as e:
self.logger.info("Invalid frequency, skipping the promise")
return
if min_frequency <= frequency <= max_frequency:
self.logger.info("Frequency is in bounds ({} MHz <= {} MHz <= {} MHz)".format(
min_frequency,
frequency,
max_frequency))
elif frequency < min_frequency:
self.logger.error("Frequency is lower than the lowest possible frequency on this hardware, please increase it ({} MHz < {} MHz)".format(
frequency,
min_frequency))
else:
self.logger.error("Frequency is higher than the highest possible frequency on this hardware, please increase it ({} MHz > {} MHz)".format(
frequency,
max_frequency))
def test(self):
"""
Called after sense() if the instance is still converging.
Returns success or failure based on sense results.
In this case, fail if the previous sensor result is negative.
"""
return self._test(result_count=1, failure_amount=1)
def anomaly(self):
"""
Called after sense() if the instance has finished converging.
Returns success or failure based on sense results.
Failure signals the instance has diverged.
In this case, fail if two out of the last three results are negative.
"""
return self._anomaly(result_count=1, failure_amount=1)
......@@ -60,6 +60,43 @@
"description": "Defines user IMPI. Must be fully filled with hostname if necessary.",
"type": "string",
"default": ""
},
"enable_multicast": {
"default": false,
"title": "Enable IPv4 multicast",
"description": "Set to true to enable IPv4 multicast",
"type": "boolean"
},
"enable_ipv6_multicast": {
"default": false,
"title": "Enable IPv6 multicast",
"description": "Set to true to enable IPv6 multicast",
"type": "boolean"
},
"enable_broadcast": {
"default": false,
"title": "Enable IPv4 broadcast",
"description": "Set to true to enable IPv4 broadcast",
"type": "boolean"
},
"route_list": {
"title": "Route list",
"patternProperties": {
".*": {
"properties": {
"ipv6_remote_addr_prefix": {
"title": "IPv6 remote address prefix",
"type": "string"
},
"prefix_len": {
"title": "Prefix length",
"type": "number"
}
},
"type": "object"
}
},
"type": "object"
}
}
}
......@@ -429,7 +429,7 @@
{#- ---- building configuration ---- #}
{#- ru_config emits RF driver configuration for specified Radio Units. #}
{%- macro ru_config(iru_dict, slapparameter_dict) %}
{%- macro ru_config(iru_dict, slapparameter_dict, support_gain_in_list) %}
// Radio Units
rf_driver: {
{%- set dev_argv = [] %}
......@@ -513,6 +513,12 @@
},
{#- emit tx/rx gain for all channels #}
{%- if support_gain_in_list %}
tx_gain: {{ tx_gainv }},
rx_gain: {{ rx_gainv }},
{%- else %}
tx_gain: {{ tx_gainv[0] }},
rx_gain: {{ rx_gainv[0] }},
{%- endif %}
{%- endmacro %}
......@@ -22,3 +22,18 @@ output = ${buildout:directory}/template.cfg
[template-ors-enb]
<= download-base
[template-ors-ue]
<= download-base
[ue-ifup]
<= download-base
recipe = slapos.recipe.template:jinja2
url = ${:_profile_base_location_}/${:_update_hash_filename_}
output= ${buildout:bin-directory}/${:_buildout_section_name_}
mode = 0755
context =
section bash bash
[frequency_outofbounds_promise]
<= download-base
......@@ -19,13 +19,30 @@
"response": "instance-ors-gnb-schema.json",
"index": 2
},
"ue": {
"title": "UE",
"software-type": "ue",
"description": "User Equipment Configuration",
"request": "instance-ors-ue-input-schema.json",
"response": "instance-ors-ue-schema.json",
"index": 3
},
"ue-slave": {
"title": "UE Sim Card",
"software-type": "ue",
"description": "User Equipment Sim Card Configuration",
"request": "sim/input-schema.json",
"response": "sim/schema.json",
"shared": true,
"index": 4
},
"core-network": {
"title": "Core Network",
"software-type": "core-network",
"description": "Core Network Configuration",
"request": "instance-core-network-input-schema.json",
"response": "instance-core-network-schema.json",
"index": 3
"index": 5
},
"core-network-slave": {
"title": "Core Network Sim Card",
......@@ -34,7 +51,7 @@
"request": "sim/input-schema.json",
"response": "sim/schema.json",
"shared": true,
"index": 4
"index": 6
}
}
}
Tests for simpleran software release
......@@ -34,7 +34,7 @@ with open("README.md") as f:
setup(
name=name,
version=version,
description="Test for SlapOS' ors-amarisoft",
description="Test for SlapOS' simpleran",
long_description=long_description,
long_description_content_type='text/markdown',
maintainer="Nexedi",
......
......@@ -314,12 +314,14 @@ class ENBTestCase4(RFTestCase4):
'enb_id': '0x17',
'gnb_id': '0x23',
'gnb_id_bits': 30,
'mbmsgw_addr': '1.4.3.2',
'gtp_addr': '4.2.3.1',
'mme_list': {
'1': {'mme_addr': '1.2.3.4'},
'1': {'mme_addr': '1.2.3.4', 's1ap_bind_addr': '2.1.3.4'},
'2': {'mme_addr': '[abcd:5::1]:78'},
},
'amf_list': {
'1': {'amf_addr': '4.3.2.1:77'},
'1': {'amf_addr': '4.3.2.1:77', 'ngap_bind_addr': '2.1.3.4'},
'2': {'amf_addr': 'dcba:5::1'},
},
'plmn_list': {
......
......@@ -43,34 +43,14 @@ param_dict = {
'testing': True,
'tx_gain': 17,
'rx_gain': 17,
'dl_earfcn': 36100,
'bandwidth': "10 MHz",
'enb_id': '0x17',
'pci': 250,
'tac': '0x1717',
'root_sequence_index': '1',
'mme_list': {
'10.0.0.1': {'mme_addr': '10.0.0.1'},
'2001:db8::1': {'mme_addr': '2001:db8::1'},
},
'core_network_plmn': '00102',
'dl_nr_arfcn': 403500,
'nr_band': 34,
'nr_bandwidth': 50,
'ssb_nr_arfcn': 403520,
'rue_addr': '192.168.99.88',
'n_antenna_dl': 2,
'n_antenna_ul': 2,
'inactivity_timer': 17,
'gnb_id': '0x17',
'gnb_id_bits': 30,
'ssb_pos_bitmap': '10',
'amf_list': {
'10.0.0.1': {'amf_addr': '10.0.0.1'},
'2001:db8::1': {'amf_addr': '2001:db8::1'},
},
'nr_handover_time_to_trigger': 40,
'nr_handover_a3_offset': 10,
'ncell_list': {
'ORS1': {
'dl_earfcn': 40000,
......@@ -95,6 +75,51 @@ param_dict = {
'tac': 2
},
},
}
enb_param_dict = {
# ors_version for tests is B39, so earfcn needs to be within B39
'dl_earfcn': 38450,
'enb_id': '0x17',
'bandwidth': "10 MHz",
'plmn_list': {
'00101': {'attach_without_pdn': True, 'plmn': '00101', 'reserved': True},
'00102': {'attach_without_pdn': False, 'plmn': '00102', 'reserved': False},
},
'tdd_ul_dl_config': '[Configuration 6] 5ms 5UL 3DL (maximum uplink)',
'mme_list': {
'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
},
},
}
gnb_param_dict = {
# ors_version for tests is B39, so dl_nr_arfcn needs to be within N39
'dl_nr_arfcn': 380000,
'nr_band': 39,
'nr_bandwidth': 40,
'ssb_nr_arfcn': 380020,
'gnb_id': '0x17',
'gnb_id_bits': 30,
'ssb_pos_bitmap': '10',
'amf_list': {
'10.0.0.1': {'amf_addr': '10.0.0.1'},
'2001:db8::1': {'amf_addr': '2001:db8::1'},
},
'nr_handover_time_to_trigger': 40,
'nr_handover_a3_offset': 10,
'xn_peers': {
'2001:db8::1': {
'xn_addr': '2001:db8::1',
......@@ -103,13 +128,26 @@ param_dict = {
'xn_addr': '2001:db8::2',
},
},
}
enb_param_dict = {
'plmn_list': {
'00101': {'attach_without_pdn': True, 'plmn': '00101', 'reserved': True},
'00102': {'attach_without_pdn': False, 'plmn': '00102', 'reserved': False},
'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
},
},
'tdd_ul_dl_config': '[Configuration 6] 5ms 5UL 3DL (maximum uplink)',
}
gnb_param_dict1 = {
'plmn_list': {
......@@ -126,15 +164,27 @@ gnb_param_dict2 = {
'tdd_ul_dl_config': '5ms 6UL 3DL 10/2 (high uplink)',
}
enb_param_dict.update(param_dict)
gnb_param_dict1.update(gnb_param_dict)
gnb_param_dict1.update(param_dict)
gnb_param_dict2.update(gnb_param_dict)
gnb_param_dict2.update(param_dict)
def test_enb_conf(self):
def load_yaml_conf(slap, name):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
slap.instance_directory, '*', 'etc', name + '.cfg'))[0]
return yamlpp_load(conf_file)
class TestENBParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_enb_conf(self):
conf = load_yaml_conf(self.slap, 'enb')
conf = yamlpp_load(conf_file)
self.assertEqual(conf['tx_gain'], [enb_param_dict['tx_gain']] * enb_param_dict['n_antenna_dl'])
self.assertEqual(conf['rx_gain'], [enb_param_dict['rx_gain']] * enb_param_dict['n_antenna_ul'])
self.assertEqual(conf['cell_list'][0]['inactivity_timer'], enb_param_dict['inactivity_timer'])
......@@ -162,12 +212,18 @@ def test_enb_conf(self):
self.assertEqual(p['cell_id'], int(conf_ncell['cell_id'], 16))
self.assertEqual(p['tac'], conf_ncell['tac'])
def test_gnb_conf1(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
class TestGNBParameters1(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
conf = load_yaml_conf(self.slap, 'enb')
conf = yamlpp_load(conf_file)
self.assertEqual(conf['tx_gain'], [gnb_param_dict1['tx_gain']] * gnb_param_dict1['n_antenna_dl'])
self.assertEqual(conf['rx_gain'], [gnb_param_dict1['rx_gain']] * gnb_param_dict1['n_antenna_ul'])
self.assertEqual(conf['nr_cell_list'][0]['inactivity_timer'], gnb_param_dict1['inactivity_timer'])
......@@ -205,12 +261,17 @@ def test_gnb_conf1(self):
self.assertEqual(int(tdd_config['ul_slots']), 1)
self.assertEqual(int(tdd_config['ul_symbols']), 2)
def test_gnb_conf2(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'enb.cfg'))[0]
class TestGNBParameters2(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict2)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
conf = yamlpp_load(conf_file)
conf = load_yaml_conf(self.slap, 'enb')
for p in conf['nr_cell_default']['plmn_list'][0]['nssai']:
sd = hex(p['sd'])
......@@ -224,55 +285,19 @@ def test_gnb_conf2(self):
self.assertEqual(int(tdd_config['ul_slots']), 6)
self.assertEqual(int(tdd_config['ul_symbols']), 10)
def test_mme_conf(self):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'mme.cfg'))[0]
conf = yamlpp_load(conf_file)
self.assertEqual(conf['plmn'], param_dict['core_network_plmn'])
def getSimParam(id=0):
return {
'sim_algo': 'milenage',
'imsi': '{0:015}'.format(1010000000000 + id),
'opc': '000102030405060708090A0B0C0D0E0F',
'amf': '0x9001',
'sqn': '000000000000',
'k': '00112233445566778899AABBCCDDEEFF',
'impu': 'impu%s' % '{0:03}'.format(id),
'impi': 'impi%s@amarisoft.com' % '{0:03}'.format(id)
}
class TestCoreNetworkParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_mme_conf(self):
def test_sim_card(self, nb_sim_cards, fixed_ips, tun_network):
conf_file = glob.glob(os.path.join(
self.slap.instance_directory, '*', 'etc', 'ue_db.cfg'))[0]
conf = yamlpp_load(conf_file)
first_ip = netaddr.IPAddress(tun_network.first)
for i in range(nb_sim_cards):
params = getSimParam(i)
for n in "sim_algo imsi opc sqn impu impi".split():
self.assertEqual(conf['ue_db'][i][n], params[n], "%s doesn't match" % n)
self.assertEqual(conf['ue_db'][i]['K'], params['k'])
self.assertEqual(conf['ue_db'][i]['amf'], int(params['amf'], 16))
p = self.requestSlaveInstanceWithId(i).getConnectionParameterDict()
p = json.loads(p['_'])
self.assertIn('info', p)
if fixed_ips:
self.assertIn('ipv4', p)
if nb_sim_cards + 2 > tun_network.size:
self.assertEqual(p['ipv4'], "Too many SIM for the IPv4 network")
else:
ip = str(first_ip + 2 + i)
self.assertEqual(p['ipv4'], ip)
self.assertEqual(conf['ue_db'][i]['pdn_list'][0]['access_point_name'], "internet")
self.assertTrue(conf['ue_db'][i]['pdn_list'][0]['default'])
self.assertEqual(conf['ue_db'][i]['pdn_list'][0]['ipv4_addr'], ip)
conf = load_yaml_conf(self.slap, 'mme')
self.assertEqual(conf['plmn'], param_dict['core_network_plmn'])
def test_monitor_gadget_url(self):
parameters = json.loads(self.computer_partition.getConnectionParameterDict()['_'])
......@@ -291,45 +316,6 @@ def test_monitor_gadget_url(self):
self.assertIn('<script src="g-chart.line.js"></script>', response.text)
self.assertIn('<script src="promise.gadget.js"></script>', response.text)
class TestENBParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(enb_param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "enb"
def test_enb_conf(self):
test_enb_conf(self)
class TestGNBParameters1(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict1)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf1(self)
class TestGNBParameters2(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(gnb_param_dict2)}
@classmethod
def getInstanceSoftwareType(cls):
return "gnb"
def test_gnb_conf(self):
test_gnb_conf2(self)
class TestCoreNetworkParameters(ORSTestCase):
@classmethod
def getInstanceParameterDict(cls):
return {'_': json.dumps(param_dict)}
@classmethod
def getInstanceSoftwareType(cls):
return "core-network"
def test_mme_conf(self):
test_mme_conf(self)
class TestENBMonitorGadgetUrl(ORSTestCase):
@classmethod
......@@ -371,6 +357,20 @@ class TestSimCard(ORSTestCase):
nb_sim_cards = 1
fixed_ips = False
tun_network = netaddr.IPNetwork('192.168.10.0/24')
@classmethod
def getSimParam(cls, id=0):
return {
'sim_algo': 'milenage',
'imsi': '{0:015}'.format(1010000000000 + id),
'opc': '000102030405060708090A0B0C0D0E0F',
'amf': '0x9001',
'sqn': '000000000000',
'k': '00112233445566778899AABBCCDDEEFF',
'impu': 'impu%s' % '{0:03}'.format(id),
'impi': 'impi%s@amarisoft.com' % '{0:03}'.format(id)
}
@classmethod
def requestDefaultInstance(cls, state='started'):
......@@ -396,7 +396,7 @@ class TestSimCard(ORSTestCase):
@classmethod
def requestSlaveInstanceWithId(cls, id=0):
software_url = cls.getSoftwareURL()
param_dict = getSimParam(id)
param_dict = cls.getSimParam(id)
return cls.slap.request(
software_release=software_url,
partition_reference="SIM-CARD-%s" % id,
......@@ -414,8 +414,33 @@ class TestSimCard(ORSTestCase):
f.seek(0)
f.truncate()
json.dump(resource, f, indent=2)
def test_sim_card(cls):
test_sim_card(cls, cls.nb_sim_cards, cls.fixed_ips, cls.tun_network)
def test_sim_card(self):
conf = load_yaml_conf(self.slap, 'ue_db')
first_ip = netaddr.IPAddress(self.tun_network.first)
for i in range(self.nb_sim_cards):
params = self.getSimParam(i)
for n in "sim_algo imsi opc sqn impu impi".split():
self.assertEqual(conf['ue_db'][i][n], params[n], "%s doesn't match" % n)
self.assertEqual(conf['ue_db'][i]['K'], params['k'])
self.assertEqual(conf['ue_db'][i]['amf'], int(params['amf'], 16))
p = self.requestSlaveInstanceWithId(i).getConnectionParameterDict()
p = json.loads(p['_'])
self.assertIn('info', p)
if self.fixed_ips:
self.assertIn('ipv4', p)
if self.nb_sim_cards + 2 > self.tun_network.size:
self.assertEqual(p['ipv4'], "Too many SIM for the IPv4 network")
else:
ip = str(first_ip + 2 + i)
self.assertEqual(p['ipv4'], ip)
self.assertEqual(conf['ue_db'][i]['pdn_list'][0]['access_point_name'], "internet")
self.assertTrue(conf['ue_db'][i]['pdn_list'][0]['default'])
self.assertEqual(conf['ue_db'][i]['pdn_list'][0]['ipv4_addr'], ip)
class TestSimCardManySim(TestSimCard):
nb_sim_cards = 10
......
......@@ -142,10 +142,10 @@ setup = ${slapos-repository:location}/software/ssh/test/
egg = slapos.test.metabase
setup = ${slapos-repository:location}/software/metabase/test/
[slapos.test.ors-amarisoft-setup]
[slapos.test.simpleran-setup]
<= setup-develop-egg
egg = slapos.test.ors-amarisoft
setup = ${slapos-repository:location}/software/ors-amarisoft/test/
egg = slapos.test.simpleran
setup = ${slapos-repository:location}/software/simpleran/test/
[slapos.test.fluentd-setup]
<= setup-develop-egg
......@@ -399,7 +399,7 @@ eggs +=
${slapos.test.mosquitto-setup:egg}
${slapos.test.nextcloud-setup:egg}
${slapos.test.nginx-push-stream-setup:egg}
${slapos.test.ors-amarisoft-setup:egg}
${slapos.test.simpleran-setup:egg}
${slapos.test.osie-coupler-setup:egg}
${slapos.test.peertube-setup:egg}
${slapos.test.plantuml-setup:egg}
......@@ -493,7 +493,7 @@ tests =
mosquitto ${slapos.test.mosquitto-setup:setup}
nextcloud ${slapos.test.nextcloud-setup:setup}
nginx-push-stream ${slapos.test.nginx-push-stream-setup:setup}
ors-amarisoft ${slapos.test.ors-amarisoft-setup:setup}
simpleran ${slapos.test.simpleran-setup:setup}
osie-coupler ${slapos.test.osie-coupler-setup:setup}
peertube ${slapos.test.peertube-setup:setup}
plantuml ${slapos.test.plantuml-setup:setup}
......
......@@ -244,7 +244,6 @@ repository = https://lab.nexedi.com/nexedi/rubygemsrecipe.git
[re6stnet-repository]
<= git-clone-repository
repository = https://lab.nexedi.com/nexedi/re6stnet.git
branch = re6st-py3
[template]
recipe = slapos.recipe.template
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment