Commit 10224d30 authored by Joanne Hugé's avatar Joanne Hugé

software/ors-amarisoft: json files for custom configuration for top

Code is in private repo, we keep the json here until we switch the
client's service to the private repo
parent df6b58d2
# ORS Amarisoft software release
How to deploy from scratch
1. Install Amarisoft binaries in /opt/amarisoft/v20XX-XX-XX with folders:
* enb: needs to containt libraries from trx_sdr
* trx_sdr
* mme
2. Install ors playbook
3. Deploy this SR
## Services
We run 2 binaries from Amarisoft LTE stack:
* **lteenb** - eNodeB software is the server accepting connection from UI (user interfaces)
* **ltemme** - Mobile Management Entity in other words core network which handles orchestration of
eNodeBs in case UI switches from one to another
Those binaries are started in foreground, originaly in screen. We don't want the binaries inside one
screen because then we cannot easily control their resource usage. Thus we make 2 on-watch services.
### ENB / GNB
Is the eNodeB (4G) or gNodeB (5G). This binary handles the radio protocols and sends and receives
IQ samples to trx_sdr driver.
### MME
Is the core network. This binary keep track of UEs and to which eNodeB they are currently connected.
It reroutes traffic when UE switches between eNodeBs.
MME also serves as a service bus thus all services must register within MME.
## Gotchas!
**trx_sdr.so** provided from archive MUST be placed next to `lteenb` binary. This library is the
only one which does not follow standard `ld` path resolution.
**rf_driver** has to be compiled and installed. Inside trx_sdr/kernel folder issue `# make` to compile the
kernel module, and then `# ./init.sh` to create devices `/dev/sdr<N>` and insert compiled module.
# THIS IS NOT A BUILDOUT FILE, despite purposedly using a compatible syntax.
# The only allowed lines here are (regexes):
# - "^#" comments, copied verbatim
# - "^[" section beginings, copied verbatim
# - lines containing an "=" sign which must fit in the following categorie.
# - "^\s*filename\s*=\s*path\s*$" where "path" is relative to this file
# But avoid directories, they are not portable.
# Copied verbatim.
# - "^\s*hashtype\s*=.*" where "hashtype" is one of the values supported
# by the re-generation script.
# Re-generated.
# - other lines are copied verbatim
# Substitution (${...:...}), extension ([buildout] extends = ...) and
# section inheritance (< = ...) are NOT supported (but you should really
# not need these here).
[template]
filename = instance.cfg
md5sum = acd9dd8dbe613e7101e62930a8380ef0
[template-ors]
filename = instance-ors.cfg
md5sum = f5c76c3443b75569eb18503dce38e783
[slaplte.jinja2]
_update_hash_filename_ = slaplte.jinja2
md5sum = 871ade334f445e22d6cb473e4d4e3522
[ru_amarisoft-stats.jinja2.py]
_update_hash_filename_ = ru/amarisoft-stats.jinja2.py
md5sum = 674dcc250c0b6bb43d8546624552fc5d
[ru_amarisoft-rf-info.jinja2.py]
_update_hash_filename_ = ru/amarisoft-rf-info.jinja2.py
md5sum = ab666fdfadbfc7d8a16ace38d295c883
[ru_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/libinstance.jinja2.cfg
md5sum = 2dda7713832be83d94522c7abb4901f9
[ru_sdr_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sdr/libinstance.jinja2.cfg
md5sum = b7906ca3a6b17963f78f680fc0842b74
[ru_lopcomm_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/lopcomm/libinstance.jinja2.cfg
md5sum = 7d05f6a3980a79bfd35677dbb8b988ee
[ru_sunwave_libinstance.jinja2.cfg]
_update_hash_filename_ = ru/sunwave/libinstance.jinja2.cfg
md5sum = bc5d82b8737b6990674b280ef2774be7
[ru_lopcomm_ncclient_common.py]
_update_hash_filename_ = ru/lopcomm/ncclient_common.py
md5sum = 8dbe6a48fc0fca4f0cbd0c746be1aeda
[ru_lopcomm_stats.jinja2.py]
_update_hash_filename_ = ru/lopcomm/stats.jinja2.py
md5sum = b7ec0025a92e0947e4ac6abc4b06bf19
[ru_lopcomm_config.jinja2.py]
_update_hash_filename_ = ru/lopcomm/config.jinja2.py
md5sum = 122726666d147447171dcae9ebf8d093
[ru_lopcomm_reset-info.jinja2.py]
_update_hash_filename_ = ru/lopcomm/reset-info.jinja2.py
md5sum = 3d78df1993211efaabd3dc6f2ec8de30
[ru_lopcomm_reset.jinja2.py]
_update_hash_filename_ = ru/lopcomm/reset.jinja2.py
md5sum = 9741fbc99aaf768e9cc3ab48925dfee5
[ru_lopcomm_software.jinja2.py]
_update_hash_filename_ = ru/lopcomm/software.jinja2.py
md5sum = 2b08bb666c5f3ab287cdddbfdb4c9249
[ru_tapsplit]
_update_hash_filename_ = ru/tapsplit
md5sum = 700aab566289619fb83ac6f3b085d983
[ru_xbuildout.py]
_update_hash_filename_ = ru/xbuildout.py
md5sum = a51171f926edd315a52841c2e7eb9fb7
[ru_capdo.c]
_update_hash_filename_ = ru/capdo.c
md5sum = 52da9fe3a569199e35ad89ae1a44c30e
[template-enb]
_update_hash_filename_ = instance-enb.jinja2.cfg
md5sum = 8b9301f26fc4ffbc7eda9c1ac8da1a46
[template-ors-enb]
_update_hash_filename_ = instance-ors-enb.jinja2.cfg
md5sum = 601d6237059fa665d3f3ffb6a78ad9ca
[template-core-network]
_update_hash_filename_ = instance-core-network.jinja2.cfg
md5sum = 326e194e9c98d58d926f89521bb95df5
[template-ue]
_update_hash_filename_ = instance-ue.jinja2.cfg
md5sum = 812a43458c21f7d0cdb2141515a236ae
[template-obsolete]
_update_hash_filename_ = instance-obsolete.jinja2.cfg
md5sum = c5f581ba01654b2aec46000abf8d0e35
[ue_db.jinja2.cfg]
filename = config/ue_db.jinja2.cfg
md5sum = 3b901e8733e6afff8940c6c318da4493
[enb.jinja2.cfg]
filename = config/enb.jinja2.cfg
md5sum = e1c40827e30d6ddcd98be35ec8569af2
[drb_lte.jinja2.cfg]
filename = config/drb_lte.jinja2.cfg
md5sum = 01eb971e2ff580da52291138495a81ca
[drb_nr.jinja2.cfg]
filename = config/drb_nr.jinja2.cfg
md5sum = 282b11d7b72b01b8325df4632d82b84d
[sib23.jinja2.asn]
filename = config/sib23.jinja2.asn
md5sum = 959523597e29b048e45ebf58f7ea4c5b
[mme.jinja2.cfg]
filename = config/mme.jinja2.cfg
md5sum = 25ae6b1022548183293f0ef0c54532a7
[dnsmasq-core-network.jinja2.cfg]
filename = config/dnsmasq-core-network.jinja2.cfg
md5sum = f167b4be5e327b276b42267e0678f577
[ru_dnsmasq.jinja2.cfg]
_update_hash_filename_ = ru/dnsmasq.jinja2.cfg
md5sum = 95f4f8fb85e0480eb3e9059b9db26540
[ims.jinja2.cfg]
filename = config/ims.jinja2.cfg
md5sum = 36281b03597252cf75169417d02fc28c
[ue.jinja2.cfg]
filename = config/ue.jinja2.cfg
md5sum = 62291a11fd36a42464901cdc81338687
[ru_lopcomm_CreateProcessingEle.jinja2.xml]
_update_hash_filename_ = ru/lopcomm/CreateProcessingEle.jinja2.xml
md5sum = e435990eb0a0d4be41efa9bd16dce09b
[ru_lopcomm_cu_config.jinja2.xml]
_update_hash_filename_ = ru/lopcomm/cu_config.jinja2.xml
md5sum = 346c911e1ac5e5001a39c8926b44c91e
[ru_lopcomm_cu_inactive_config.jinja2.xml]
_update_hash_filename_ = ru/lopcomm/cu_inactive_config.jinja2.xml
md5sum = 9d48c35f9939446ce75ae9f85e44c26a
[software.cfg.html]
_update_hash_filename_ = gadget/software.cfg.html
md5sum = 61a2f783fbf683a34aed3d13e00baca2
[promise.gadget.js]
_update_hash_filename_ = gadget/promise.gadget.js
md5sum = 330f5f07806f1da11cd05bb8e4b52e55
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Cell. Common properties",
"type": "object",
"required": [
"cell_type",
"rf_mode",
"pci",
"cell_id",
"bandwidth",
"ru"
],
"properties": {
"cell_type": {
"type": "string"
},
"cell_kind": {
"type": "string",
"const": "enb"
},
"rf_mode": {
"title": "RF mode",
"description": "Mode for TX/RX radio multiplexing: Frequency- or Time- Domain Division",
"type": "string",
"enum": ["fdd", "tdd"],
"propertyOrder": 101
},
"pci": {
"title": "Physical Cell ID",
"description": "Physical Cell ID",
"type": "integer"
},
"cell_id": {
"title": "Cell ID",
"description": "Cell ID",
"type": "string"
},
"bandwidth": {
"title": "Bandwidth",
"description": "Downlink Bandwidth (in MHz)",
"type": "number"
},
"root_sequence_index": {
"title": "Root Sequence Index",
"type": "integer"
},
"inactivity_timer": {
"title": "Inactivity Timer",
"description": "Send RRC connection release after this time (in ms) of network inactivity.",
"type": "number",
"default": 10000
},
"ru": {
"$ref": "#/$defs/ru-of-cell",
"propertyOrder": 9999
}
},
"$defs": {
"ru-of-cell": {
"title": "Radio Unit",
"oneOf": [
{
"title": "Shared Radio Unit",
"description": "Use radio unit defined in separate shared instance",
"type": "object",
"required": ["ru_type", "ru_ref"],
"properties": {
"ru_type": {
"type": "string",
"const": "ru_ref"
},
"ru_ref": {
"title": "RU Reference",
"description": "Reference of shared radio unit instance",
"type": "string"
}
}
},
{
"title": "Shared Radio Unit of a Cell",
"description": "Use the same radio unit as referenced cell instance does",
"type": "object",
"required": ["ru_type", "ruincell_ref"],
"properties": {
"ru_type": {
"type": "string",
"const": "ruincell_ref"
},
"ruincell_ref": {
"title": "Cell Reference",
"description": "Reference of cell instance whose radio unit to share",
"type": "string"
}
}
},
{ "$ref": "../ru/sdr/input-schema.json" },
{ "$ref": "../ru/lopcomm/input-schema.json" },
{ "$ref": "../ru/sunwave/input-schema.json" }
]
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Cell",
"type": "object",
"oneOf": [
{ "$ref": "../cell/lte/input-schema.json" },
{ "$ref": "../cell/nr/input-schema.json" }
]
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "LTE Cell",
"type": "object",
"required": [
"cell_type",
"rf_mode",
"pci",
"cell_id",
"bandwidth",
"ru",
"dl_earfcn",
"tac"
],
"properties": {
"$ref": "../../cell/common.json#/properties",
"cell_type": {
"$ref": "#/properties/cell_type",
"const": "lte"
},
"tdd_ul_dl_config": {
"title": "TDD Configuration",
"type": "string",
"enum": [
"[Configuration 2] 5ms 2UL 6DL (default)",
"[Configuration 6] 5ms 5UL 3DL (maximum uplink)"
],
"default": "[Configuration 2] 5ms 2UL 6DL (default)",
"options": {
"dependencies": {
"rf_mode": "tdd"
}
}
},
"bandwidth": {
"$ref": "#/properties/bandwidth",
"enum": [
1.4,
3,
5,
10,
15,
20
]
},
"dl_earfcn": {
"title": "DL EARFCN",
"description": "Downlink E-UTRA Absolute Radio Frequency Channel Number of the cell",
"type": "integer"
},
"ul_earfcn": {
"title": "UL EARFCN",
"description": "Uplink E-UTRA Absolute Radio Frequency Channel Number of the cell. By default a frequency corresponding to dl_earfcn is chosen.",
"type": "integer"
},
"tac": {
"title": "Tracking Area Code",
"description": "Tracking Area Code in hexadecimal representation (range 0x0000 to 0xffff)",
"type": "string"
},
"root_sequence_index": {
"$ref": "#/properties/root_sequence_index",
"description": "Range: 0 to 837. Set the PRACH root sequence index (SIB2.rootSequenceIndex field). It must be different for each neighbour cell operating on the same frequency and sharing the same PRACH configuration.",
"default": 204
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "NR Cell",
"type": "object",
"required": [
"cell_type",
"rf_mode",
"pci",
"cell_id",
"bandwidth",
"ru",
"dl_nr_arfcn",
"nr_band"
],
"properties": {
"$ref": "../../cell/common.json#/properties",
"cell_type": {
"$ref": "#/properties/cell_type",
"const": "nr"
},
"tdd_ul_dl_config": {
"title": "TDD Configuration",
"type": "string",
"enum": [
"5ms 2UL 7DL 4/6 (default)",
"2.5ms 1UL 3DL 2/10",
"5ms 8UL 1DL 2/10 (maximum uplink)"
],
"default": "5ms 2UL 7DL 4/6 (default)",
"options": {
"dependencies": {
"rf_mode": "tdd"
}
}
},
"bandwidth": {
"$ref": "#/properties/bandwidth"
},
"dl_nr_arfcn": {
"title": "DL NR ARFCN",
"description": "Downlink NR Absolute Radio Frequency Channel Number of the cell",
"type": "integer"
},
"nr_band": {
"title": "NR band",
"description": "NR band number",
"type": "integer"
},
"ul_nr_arfcn": {
"title": "UL NR ARFCN",
"description": "Uplink NR Absolute Radio Frequency Channel Number of the cell. By default a frequency corresponding to dl_nr_arfcn and nr_band is chosen.",
"type": "integer"
},
"ssb_nr_arfcn": {
"title": "SSB NR ARFCN",
"description": "SSB NR Absolute Radio Frequency Channel Number of the cell. If set it must be an element of global synchronization raster and be at offset from center DL frequency that aligns with SSB subcarrier spacing of selected band. By default a valid frequency nearby dl_nr_arfcn is chosen.",
"type": "integer"
},
"ssb_pos_bitmap": {
"title": "SSB Position Bitmap",
"description": "SSB position bitmap in bits (4, 8 or 64 bits depending on the DL frequency).",
"type": "string",
"default": "10000000"
},
"root_sequence_index": {
"$ref": "#/properties/root_sequence_index",
"description": "Range 0 to 837 for PRACH format up to 3, 0 to 137 otherwise. prach-RootSequenceIndex parameter. It must be different for each neighbour cell operating on the same frequency and sharing the same PRACH configuration.",
"default": 1
}
},
"$defs": {
"tac": {
"title": "Tracking Area Code",
"description": "Integer (range 0 to 16777215)",
"type": "number"
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by Cell instantiation (stub)",
"type": "object",
"properties": {}
}
Changelog
=========
Version 1.0.344 (2023-11-03)
-------------
* Set dpc_snr_target to 25 for PUSCH also
Version 1.0.341 (2023-10-20)
-------------
* Publish amarisoft version and license expiration information
* Add network name parameter
Version 1.0.340 (2023-10-20)
-------------
* Update RRH firmware and reset
Version 1.0.339 (2023-10-16)
-------------
* Lopcomm firmware update
* RRH reset (reboot) function added
* Fix cpri_tx_dbm parameter
* Print RRH IPv6 and firmware information
Version 1.0.336 (2023-09-25)
-------------
* Support on Lopcomm RRH via netconf
- Lopcomm firmware auto-upgrade and verification
- Up to 4T4R
- Netconf access verification promise
- PA output power alarm
- Default value added for B1
* fix some bugs
Version 1.0.332 (2023-09-04)
-------------
* Add 4G Intra eNB Handover
* Add public websocket URL protected by password
* Reorganize softwares: ORS now need to use software-tdd-ors or software-fdd-ors
* Support multiple cells for BBUs
Version 1.0.330 (2023-07-19)
-------------
* Change Slice Differentiator input parameter to hexadecimal representation
* Add TDD Configurations with maximum uplink
* Modify reference power signal to improve radio link over long distances
* Add Tracking Area Code (TAC) parameter to eNB
* Publish useful values:
- Frequency and band
- Current TX and RX gain
- Estimated TX power in dB and W based on https://handbook.rapid.space/rapidspace-ORS.tx.gain
- ORS frequency range rating
- ORS version
Version 1.0.326 (2023-06-14)
-------------
* Add DHCP for Lopcomm RU's M-plane
* Add support for FDD
* Add more parameters and tests for lopcomm RU
Version 1.0.323 (2023-05-17)
-------------
* Add support for first version of MCPTT (Mission Critical Push To Talk)
Version 1.0.321 (2023-05-05)
-------------
* Remove RRH options from ORS software releases
* Add custom TDD UL DL configuration
* Add time_to_trigger and a3_offset gNB XnAP and NGAP NR handover options
Version 1.0.320 (2023-04-26)
----------------------------
* Add support for inter gNB XnAP and NGAP NR handover
Version 1.0.317 (2023-04-18)
---------------------------
* Add support for inter gNB NR handover
Version 1.0.316 (2023-04-14)
----------------------------
* Remove enb-epc, gnb-epc and epc software types, the software types are now:
- enb
- gnb
- core-network (replaces epc software type)
Version 1.0.312 (2023-03-20)
----------------------------
* Add promise to test if reception is saturated
* Add gadget from SR to display on Monitor APP
* Add IMSI in connection parameters when SIM gets attached
* Add carrier control for Lopcomm RRH
Version 1.0.308 (2023-02-09)
----------------------------
* Add support for IPv6 in UEs if available
* Use latest amarisoft version on ORS if available
* Add gnb_id_bits parameter
* Use promises from slapos.toolbox repository
* Rotate and add timestamps in enb-output.log, gnb-output.log, mme-output.log etc...
* Add support for Lopcomm RRH
* Remove UE power emission limitation
interface={{ slap_configuration.get('tun-name', '') }}
port=5353
{%- set filtered_slave_instance_list = [] %}
{%- for slave_instance in slap_configuration.get('slave-instance-list', []) %}
{%- if slave_instance.get('_', '') != '' %}
{%- set slave = json_module.loads(slave_instance.pop('_')) %}
{%- else %}
{%- set slave = slave_instance %}
{%- endif %}
{%- if slave.get('subdomain', '') != '' %}
{%- do filtered_slave_instance_list.append(slave) %}
{%- endif %}
{%- endfor %}
{% for i, slave in enumerate(filtered_slave_instance_list) -%}
address=/{{ slave['subdomain'] }}.{{ slap_configuration['configuration'].get('local_domain', '') }}/{{ slave.get('ip', '') }}
{% endfor -%}
This diff is collapsed.
{%- set B = xbuildout.encode -%}
// DRB configuration for NR cell {{ B(cell_ref) }} @ {{ B(ru_ref) }}.
[
{
qci: 1,
use_for_mr_dc_scg: false,
ims_dedicated_bearer: true,
pdcp_config: {
discardTimer: 100,
pdcp_SN_SizeUL: 12,
pdcp_SN_SizeDL: 12,
statusReportRequired: false,
outOfOrderDelivery: false,
t_Reordering: 0,
},
rlc_config: {
ul_um: {
sn_FieldLength: 6,
},
dl_um: {
sn_FieldLength: 6,
t_Reassembly: 50,
},
},
logical_channel_config: {
priority: 7,
prioritisedBitRate: 0,
bucketSizeDuration: 100,
logicalChannelGroup: 1,
},
},
{
qci: 2,
use_for_mr_dc_scg: false,
ims_dedicated_bearer: true,
pdcp_config: {
discardTimer: 150,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: false,
outOfOrderDelivery: false,
t_Reordering: 0,
},
rlc_config: {
ul_um: {
sn_FieldLength: 12,
},
dl_um: {
sn_FieldLength: 12,
t_Reassembly: 50,
},
},
logical_channel_config: {
priority: 8,
prioritisedBitRate: 0,
bucketSizeDuration: 100,
logicalChannelGroup: 1,
},
},
{
qci: 3,
pdcp_config: {
discardTimer: 100,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: false,
outOfOrderDelivery: false,
t_Reordering: 0,
},
rlc_config: {
ul_um: {
sn_FieldLength: 12,
},
dl_um: {
sn_FieldLength: 12,
t_Reassembly: 50,
},
},
logical_channel_config: {
priority: 7,
prioritisedBitRate: 0,
bucketSizeDuration: 100,
logicalChannelGroup: 2,
},
},
{
qci: 4,
pdcp_config: {
discardTimer: 0,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: true,
outOfOrderDelivery: false,
},
rlc_config: {
ul_am: {
sn_FieldLength: 18,
t_PollRetransmit: 80,
pollPDU: 64,
pollByte: 125,
maxRetxThreshold: 4,
},
dl_am: {
sn_FieldLength: 18,
t_Reassembly: 80,
t_StatusProhibit: 10,
},
},
logical_channel_config: {
priority: 9,
prioritisedBitRate: 8,
bucketSizeDuration: 100,
logicalChannelGroup: 3,
},
},
{
qci: 65,
use_for_mr_dc_scg: false,
ims_dedicated_bearer: true,
pdcp_config: {
discardTimer: 100,
pdcp_SN_SizeUL: 12,
pdcp_SN_SizeDL: 12,
statusReportRequired: false,
outOfOrderDelivery: false,
t_Reordering: 0,
},
rlc_config: {
ul_um: {
sn_FieldLength: 6,
},
dl_um: {
sn_FieldLength: 6,
t_Reassembly: 50,
},
},
logical_channel_config: {
priority: 5,
prioritisedBitRate: 0,
bucketSizeDuration: 100,
logicalChannelGroup: 4,
},
},
{
qci: 66,
use_for_mr_dc_scg: false,
ims_dedicated_bearer: true,
pdcp_config: {
discardTimer: 150,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: false,
outOfOrderDelivery: false,
t_Reordering: 0,
},
rlc_config: {
ul_um: {
sn_FieldLength: 12,
},
dl_um: {
sn_FieldLength: 12,
t_Reassembly: 50,
},
},
logical_channel_config: {
priority: 7,
prioritisedBitRate: 0,
bucketSizeDuration: 100,
logicalChannelGroup: 4,
},
},
{
qci: 67,
use_for_mr_dc_scg: false,
ims_dedicated_bearer: true,
pdcp_config: {
discardTimer: 100,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: false,
outOfOrderDelivery: false,
t_Reordering: 0,
},
rlc_config: {
ul_um: {
sn_FieldLength: 12,
},
dl_um: {
sn_FieldLength: 12,
t_Reassembly: 50,
},
},
logical_channel_config: {
priority: 6,
prioritisedBitRate: 0,
bucketSizeDuration: 100,
logicalChannelGroup: 5,
},
},
{
qci: 5,
use_for_mr_dc_scg: false,
pdcp_config: {
discardTimer: 0,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: true,
outOfOrderDelivery: false,
},
rlc_config: {
ul_am: {
sn_FieldLength: 18,
t_PollRetransmit: 80,
pollPDU: 64,
pollByte: 125,
maxRetxThreshold: 4,
},
dl_am: {
sn_FieldLength: 18,
t_Reassembly: 80,
t_StatusProhibit: 10,
},
},
logical_channel_config: {
priority: 6,
prioritisedBitRate: 8,
bucketSizeDuration: 100,
logicalChannelGroup: 4,
},
},
{
qci: 6,
pdcp_config: {
discardTimer: 0,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: true,
outOfOrderDelivery: false,
},
rlc_config: {
ul_am: {
sn_FieldLength: 18,
t_PollRetransmit: 80,
pollPDU: 64,
pollByte: 125,
maxRetxThreshold: 4,
},
dl_am: {
sn_FieldLength: 18,
t_Reassembly: 80,
t_StatusProhibit: 10,
},
},
logical_channel_config: {
priority: 10,
prioritisedBitRate: 8,
bucketSizeDuration: 100,
logicalChannelGroup: 5,
},
},
{
qci: 7,
pdcp_config: {
discardTimer: 100,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: false,
outOfOrderDelivery: false,
t_Reordering: 0,
},
rlc_config: {
ul_um: {
sn_FieldLength: 12,
},
dl_um: {
sn_FieldLength: 12,
t_Reassembly: 50,
},
},
logical_channel_config: {
priority: 11,
prioritisedBitRate: 0,
bucketSizeDuration: 100,
logicalChannelGroup: 6,
},
},
{
qci: 8,
pdcp_config: {
discardTimer: 0,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: true,
outOfOrderDelivery: false,
},
rlc_config: {
ul_am: {
sn_FieldLength: 18,
t_PollRetransmit: 80,
pollPDU: 64,
pollByte: 125,
maxRetxThreshold: 4,
},
dl_am: {
sn_FieldLength: 18,
t_Reassembly: 80,
t_StatusProhibit: 10,
},
},
logical_channel_config: {
priority: 12,
prioritisedBitRate: 8,
bucketSizeDuration: 100,
logicalChannelGroup: 7,
},
},
{
qci: 9,
pdcp_config: {
discardTimer: 0,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: true,
outOfOrderDelivery: false,
},
rlc_config: {
ul_am: {
sn_FieldLength: 18,
t_PollRetransmit: 80,
pollPDU: 64,
pollByte: 125,
maxRetxThreshold: 4,
},
dl_am: {
sn_FieldLength: 18,
t_Reassembly: 80,
t_StatusProhibit: 10,
},
},
logical_channel_config: {
priority: 13,
prioritisedBitRate: 8,
bucketSizeDuration: 100,
logicalChannelGroup: 7,
},
},
{
qci: 69,
use_for_mr_dc_scg: false,
pdcp_config: {
discardTimer: 0,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: true,
outOfOrderDelivery: false,
},
rlc_config: {
ul_am: {
sn_FieldLength: 18,
t_PollRetransmit: 80,
pollPDU: 64,
pollByte: 125,
maxRetxThreshold: 4,
},
dl_am: {
sn_FieldLength: 18,
t_Reassembly: 80,
t_StatusProhibit: 10,
},
},
logical_channel_config: {
priority: 4,
prioritisedBitRate: 8,
bucketSizeDuration: 100,
logicalChannelGroup: 4,
},
},
{
qci: 70,
pdcp_config: {
discardTimer: 0,
pdcp_SN_SizeUL: 18,
pdcp_SN_SizeDL: 18,
statusReportRequired: true,
outOfOrderDelivery: false,
},
rlc_config: {
ul_am: {
sn_FieldLength: 18,
t_PollRetransmit: 80,
pollPDU: 64,
pollByte: 125,
maxRetxThreshold: 4,
},
dl_am: {
sn_FieldLength: 18,
t_Reassembly: 80,
t_StatusProhibit: 10,
},
},
logical_channel_config: {
priority: 11,
prioritisedBitRate: 8,
bucketSizeDuration: 100,
logicalChannelGroup: 5,
},
},
]
This diff is collapsed.
{
log_options: "all.level=debug,all.max_size=32",
log_filename: "{{ directory['log'] }}/ims.log",
sip_addr: [
{addr: "{{ slap_configuration['tun-ipv4-addr'] }}", bind_addr: "0.0.0.0", port_min: 10000, port_max: 20000},
{#" slap_configuration['tun-ipv6-addr'] ",#}
],
mms_server_bind_addr: "{{ netaddr.IPAddress(netaddr.IPNetwork(slap_configuration['tun-ipv4-network']).first) + 1 }}:1111",
sctp_addr: "{{ slap_configuration['configuration.ims_addr'] }}",
cx_server_addr: "127.0.1.100",
cx_bind_addr: "{{ slap_configuration['configuration.ims_addr'] }}",
rx_server_addr: "127.0.1.100",
rx_bind_addr: "{{ slap_configuration['configuration.ims_addr'] }}",
domain: "{{ slap_configuration['configuration.domain'] }}",
include "{{ slap_configuration['ue_db_path'] }}",
{# Example of of s6a connection #}
{# s6: { #}
{# server_addr: "", #}
{# bind_addr: "", #}
{# origin_realm: "", #}
{# origin_host: "", #}
{# }, #}
echo: [
"tel:666",
"tel:+666",
{impu: "tel:404", code: 404},
{impu: "urn:service:sos", anonymous: true, authentication: false},
{impu: "urn:service:sos.police", anonymous: true, authentication: false},
],
precondition: "on",
"100rel": true,
ipsec_aalg_list: ["hmac-md5-96", "hmac-sha-1-96"],
ipsec_ealg_list: ["null", "aes-cbc", "des-cbc", "des-ede3-cbc"],
mt_call_sdp_file: "{{ directory['software'] }}/mme/config/mt_call.sdp",
ue_db_filename: "{{ directory['var'] }}/lte_ue_ims.db",
}
{
log_options: "all.level=error,all.max_size=0,nas.level=debug,nas.max_size=1,s1ap.level=debug,s1ap.max_size=1,ngap.level=debug,ngap.max_size=1,file.rotate=1G,file.path=/dev/null",
log_filename: "{{ directory['log'] }}/mme.log",
{% if slapparameter_dict.get('external_enb_gnb', '') %}
{% if slapparameter_dict.get('use_ipv4', False) %}
gtp_addr: "{{ gtp_addr_v4 }}",
{% else %}
gtp_addr: "{{ gtp_addr_v6 }}",
{% endif %}
{% else %}
gtp_addr: "{{ slap_configuration['configuration.gtp_addr'] }}",
{% endif %}
plmn: "{{ slapparameter_dict.get('core_network_plmn', "00101") }}",
mme_group_id: 32769,
mme_code: 1,
ims_vops_eps: true,
ims_vops_5gs_3gpp: true,
ims_vops_5gs_n3gpp: true,
emergency_number_list: [
{ category: 0x1f, digits: "911" },
{ category: 0x1f, digits: "112" },
],
rx: {
qci: {audio: 1, video: 2},
},
network_name: "{{ slapparameter_dict.get('network_name', 'RAPIDSPACE') }}",
network_short_name: "{{ slapparameter_dict.get('network_short_name', 'RAPIDSPACE') }}",
cp_ciot_opt: true,
nr_support: true,
eps_5gs_interworking: "with_n26",
fifteen_bearers: false,
ims_list: [
{
ims_addr: "{{ slap_configuration['configuration.ims_addr'] }}",
bind_addr: "{{ slap_configuration['configuration.ims_bind'] }}"
}
],
pdn_list: [
{
{% if slap_configuration.get('tun-ipv6-network', '') %}
pdn_type: "ipv4v6",
first_ipv6_prefix: "{{ netaddr.IPAddress(slap_configuration.get('tun-ipv6-addr', '')) + 1 }}",
last_ipv6_prefix: "{{ netaddr.IPAddress(netaddr.IPNetwork(slap_configuration.get('tun-ipv6-network', '')).last) - 1 }}",
{% if slapparameter_dict.get('local_domain', '') %}
dns_addr: ["{{ slap_configuration.get('tun-ipv4-addr', '') }}"],
{% else %}
dns_addr: ["8.8.8.8", "2001:4860:4860::8888"],
{% endif %}
{% else %}
pdn_type: "ipv4",
dns_addr: "8.8.8.8",
{% endif %}
tun_ifname: "{{ slap_configuration.get('tun-name', '') }}",
access_point_name: ["default", "internet", "ims", "sos"],
{% if slap_configuration.get('tun-name', '') %}
first_ip_addr: "{{ netaddr.IPAddress(netaddr.IPNetwork(slap_configuration.get('tun-ipv4-network', '')).first) + 2 }}",
last_ip_addr: "{{ netaddr.IPAddress(netaddr.IPNetwork(slap_configuration.get('tun-ipv4-network', '')).last) - 1 }}",
{% endif %}
p_cscf_addr: ["{{ slap_configuration.get('tun-ipv4-addr', '') }}"],
erabs: [
{
qci: 9,
priority_level: 15,
pre_emption_capability: "shall_not_trigger_pre_emption",
pre_emption_vulnerability: "not_pre_emptable",
},
],
},
],
tun_setup_script: "{{ ifup_empty }}",
ue_to_ue_forwarding: false,
nas_cipher_algo_pref: [ ],
nas_integ_algo_pref: [ 2, 1 ],
include "{{ slap_configuration['ue_db_path'] }}",
ue_db_filename: "{{ directory['var'] }}/lte_ue.db"
}
{%- set B = xbuildout.encode -%}
/* SIB2/SIB3 for {{ cell.cell_type | upper }} cell {{ B(cell_ref) }} @ {{ B(ru_ref) }}. */
{
message c1: systemInformation: {
criticalExtensions systemInformation-r8: {
sib-TypeAndInfo {
sib2: {
radioResourceConfigCommon {
rach-ConfigCommon {
preambleInfo {
numberOfRA-Preambles n52
},
powerRampingParameters {
powerRampingStep dB2,
preambleInitialReceivedTargetPower dBm-104
},
ra-SupervisionInfo {
preambleTransMax n10,
ra-ResponseWindowSize sf10,
mac-ContentionResolutionTimer sf40
},
maxHARQ-Msg3Tx 5
},
bcch-Config {
modificationPeriodCoeff n4
},
pcch-Config {
defaultPagingCycle rf128,
nB oneT
},
prach-Config {
rootSequenceIndex 0, /* patched by eNB */
prach-ConfigInfo {
prach-ConfigIndex 4, /* patched by eNB */
highSpeedFlag FALSE,
zeroCorrelationZoneConfig 11,
prach-FreqOffset 4 /* patched by eNB */
}
},
pdsch-ConfigCommon {
{% if ors %}
{%- if ors['one-watt'] %}
referenceSignalPower {{ (ru.tx_gain | int) - 54 }}, /* patched by eNB */
{%- else %}
referenceSignalPower {{ (ru.tx_gain | int) - 35 }}, /* patched by eNB */
{%- endif %}
{% else %}
referenceSignalPower -8, /* patched by eNB */
{% endif %}
p-b 1 /* patched by eNB */
},
pusch-ConfigCommon {
pusch-ConfigBasic {
n-SB 1,
hoppingMode interSubFrame,
pusch-HoppingOffset 8, /* patched by eNB */
enable64QAM FALSE /* patched by eNB */
},
ul-ReferenceSignalsPUSCH {
groupHoppingEnabled FALSE,
groupAssignmentPUSCH 0,
sequenceHoppingEnabled FALSE,
cyclicShift 0
}
},
pucch-ConfigCommon {
deltaPUCCH-Shift ds2,
nRB-CQI 4, /* patched by eNB */
nCS-AN 0,
n1PUCCH-AN 12 /* patched by eNB */
},
soundingRS-UL-ConfigCommon setup: {
srs-BandwidthConfig bw2, /* patched by eNB */
srs-SubframeConfig sc3, /* patched by eNB */
ackNackSRS-SimultaneousTransmission TRUE
},
uplinkPowerControlCommon {
p0-NominalPUSCH -85,
alpha al1,
p0-NominalPUCCH -117,
deltaFList-PUCCH {
deltaF-PUCCH-Format1 deltaF0,
deltaF-PUCCH-Format1b deltaF3,
deltaF-PUCCH-Format2 deltaF1,
deltaF-PUCCH-Format2a deltaF2,
deltaF-PUCCH-Format2b deltaF2
},
deltaPreambleMsg3 4
},
ul-CyclicPrefixLength len1
},
ue-TimersAndConstants {
t300 ms200,
t301 ms200,
t310 ms200,
n310 n6,
t311 ms10000,
n311 n5
},
freqInfo {
additionalSpectrumEmission 1
},
timeAlignmentTimerCommon infinity
},
sib3: {
cellReselectionInfoCommon {
q-Hyst dB2
},
cellReselectionServingFreqInfo {
s-NonIntraSearch 3,
threshServingLow 2,
cellReselectionPriority 6
},
intraFreqCellReselectionInfo {
q-RxLevMin -61,
p-Max 23,
s-IntraSearch 5,
presenceAntennaPort1 TRUE,
neighCellConfig '01'B,
t-ReselectionEUTRA 1
}
}
}
}
}
}
{%- import 'slaplte.jinja2' as slaplte with context %}
{%- set B = slaplte.B %}
{%- set J = slaplte.J %}
{%- set jcell_ru_ref = slaplte.jcell_ru_ref %}
{#- for standalone testing via slapos-render-config.py
NOTE: keep in sync with instance-ue.jinja2.cfg and ru/libinstance.jinja2.cfg #}
{%- if _standalone is defined %}
{%- set iru_dict = {} %}
{%- set icell_dict = {} %}
{%- set iue_dict = {} %}
{%- do slaplte.load_iru_and_icell(iru_dict, icell_dict, icell_kind='ue') %}
{%- do slaplte.load_iue(iue_dict) %}
{%- do slaplte.check_loaded_everything() %}
{%- endif %}
{#- start of the config -#}
{
log_options: "all.level=error,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1,phy.level=info,file.rotate=1G,file.path=/dev/null",
log_filename: "{{ directory['log'] }}/ue.log",
rue_bind_addr: "{{ pub_info['rue_bind_addr'] }}",
com_addr: "{{ pub_info['com_addr'] }}",
{# instantiate radio units #}
{{ slaplte.ru_config(iru_dict, slapparameter_dict) }}
cell_groups: [{
// LTE cells
group_type: "lte",
multi_ue: true,
cells: [
{%- for cell_ref, icell in icell_dict|dictsort %}
{%- set cell = icell['_'] %}
{%- if cell.cell_type == 'lte' %}
{%- set ru_ref = J(jcell_ru_ref(icell)) %}
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
// {{ B(cell_ref) }}
{
rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }},
n_antenna_ul: {{ ru.n_antenna_ul }},
dl_earfcn: {{ cell.dl_earfcn }},
ul_earfcn: {{ cell.ul_earfcn }},
bandwidth: {{ cell.bandwidth }},
global_timing_advance: -1,
},
{%- endif %}
{%- endfor %}
],
pdcch_decode_opt: false,
pdcch_decode_opt_threshold: 0.1,
}, {
// NR cells
group_type: "nr",
multi_ue: true,
cells: [
{%- for cell_ref, icell in icell_dict|dictsort %}
{%- set cell = icell['_'] %}
{%- if cell.cell_type == 'nr' %}
{%- set ru_ref = J(jcell_ru_ref(icell)) %}
{%- set iru = iru_dict[ru_ref] %}
{%- set ru = iru['_'] %}
// {{ B(cell_ref) }}
{
rf_port: {{ ru._rf_port }},
n_antenna_dl: {{ ru.n_antenna_dl }},
n_antenna_ul: {{ ru.n_antenna_ul }},
band: {{ cell.nr_band }},
dl_nr_arfcn: {{ cell.dl_nr_arfcn }},
ul_nr_arfcn: {{ cell.ul_nr_arfcn }},
ssb_nr_arfcn: {{ cell.ssb_nr_arfcn }},
bandwidth: {{ cell.bandwidth }},
subcarrier_spacing: {{ cell.subcarrier_spacing }},
},
{%- endif %}
{%- endfor %}
]
}],
ue_list: [
{%- for ue_ref, iue in iue_dict|dictsort %}
{%- set ue = iue['_'] %}
// {{ B(ue_ref) }}
{
sim_algo: "{{ ue.sim_algo }}",
opc: "{{ ue.opc }}",
amf: {{ ue.amf }},
sqn: "{{ ue.sqn }}",
impu: "{{ ue.impu }}",
impi: "{{ ue.impi }}",
imsi: "{{ ue.imsi }}",
K: "{{ ue.k }}",
rue_addr: "{{ ue.rue_addr }}",
{%- if ue.ue_type == 'lte' %}
as_release: 13,
ue_category: 13,
{%- elif ue.ue_type == 'nr' %}
as_release: 15,
ue_category: "nr",
{%- else %}
{%- do bug('unreachable') %}
{%- endif %}
tun_setup_script: "ue-ifup",
apn: "internet",
},
{%- endfor %}
],
}
ue_db: [
{%- for i, slave in enumerate(slap_configuration['sim_list']) %}
{%- set s = json_module.loads(slave.pop('_')) %}
{%- if i == 0 -%}
{
{%- else -%}
, {
{%- endif %}
sim_algo: "{{ s.get('sim_algo', 'milenage') }}",
imsi: "{{ s.get('imsi', '') }}",
opc: "{{ s.get('opc', '') }}",
amf: {{ s.get('amf', '0x9001') }},
sqn: "{{ s.get('sqn', '000000000000') }}",
K: "{{ s.get('k', '') }}",
impu: "{{ s.get('impu', '') }}",
impi: "{{ s.get('impi', '') }}",
{%- if "ip" in s %}
pdn_list:[{
access_point_name: "internet",
default: true,
ipv4_addr: "{{ s['ip'] }}"
}]
{%- endif %}
}
{%- endfor -%}
]
/*global window, rJS, RSVP, LineChart*/
/*jslint indent:2, maxlen:80, nomen:true */
(function () {
"use strict";
rJS(window)
.declareAcquiredMethod("getPromiseDocument", "getPromiseDocument")
.declareMethod("render", function () {
var gadget = this;
return gadget.getPromiseDocument(
"check-cpu-temperature",
"log/monitor/promise/check-cpu-temperature.json.log"
)
.push(function (result) {
//gadget.element.textContent = result;
result = result.replace(/\'/g, "\"");
var item = result.split("\n"),
tmp = "",
data_tmp = "",
data_list = [],
time = [],
data = [],
i = 0,
data_list_list,
canvas,
label,
tooltip,
line_chart;
item = JSON.parse(JSON.stringify(item));
for (i = 0; i < 30; i += 1) {
data_list.push(item[i]);
data_list_list = JSON.parse(data_list[i]);
if (data_list_list.hasOwnProperty("time")
&& data_list_list.hasOwnProperty("data")) {
tmp = data_list_list.time.split(" ")[1].split(",")[0];
data_tmp = data_list_list.data.cpu_temperature;
}
time.push(tmp);
data.push(data_tmp);
gadget.time = time;
gadget.data = data;
}
canvas = gadget.element.children.line;
data = gadget.data;
label = gadget.time;
tooltip = ['Twelve', 'Fifteen', 'Thirteen', 'Twenty-two',
'Eight', 'Twelve', 'Thirdy-one', 'Three', 'Five'];
line_chart = new LineChart(canvas, data, label, tooltip);
line_chart.draw();
line_chart.tooltipOn('mousemove');
});
});
}());
\ No newline at end of file
<html>
<head>
<script src="rsvp.js"></script>
<script src="renderjs.js"></script>
<script src="g-chart.line.js"></script>
<script src="promise.gadget.js"></script>
<style type="text/css">
.tooltip-chart {
position: fixed;
z-index: 1000;
transform: translate(-50%, -120%);
padding: 10px;
background-color: white;
border-radius: 5px;
text-align: center;
min-width: 100px;
border: 1px solid #000;
box-shadow: 0 0 10px 5px #000;
}
</style>
</head>
<body>
<canvas id="line" width="1600" height="350"></canvas>
</body>
</html>
{%- set dns_slave_instance_list = [] %}
{%- set sim_slave_instance_list = [] %}
{%- set fixed_ip = slapparameter_dict.get("fixed_ips", False) %}
{%- for slave in slave_instance_list %}
{%- set slave_parameters = json_module.loads(slave['_']) %}
{%- if slave_parameters.get('subdomain', '') != '' %}
{%- do dns_slave_instance_list.append(slave) %}
{%- elif slave_parameters.get('imsi', '') != '' %}
{%- do sim_slave_instance_list.append(slave) %}
{%- endif %}
{%- endfor %}
{% set part_list = [] -%}
{%- for slave in sim_slave_instance_list %}
{%- set slave_parameters = json_module.loads(slave['_']) %}
{% set slave_reference = slave.get('slave_reference', '') %}
{% set publish_section_title = 'publish-%s' % slave_reference %}
{% do part_list.append(publish_section_title) %}
[{{ publish_section_title }}]
recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ slave_reference }}
info = Your SIM card with IMSI {{ slave_parameters.get('imsi', '') }} has been attached to service ${slap-configuration:instance-title}.
{%- if fixed_ip %}
ipv4 = ${sim-ip-configuration:{{slave_reference}}}
{%- endif %}
{%- endfor %}
[sim-ip-configuration]
recipe = slapos.recipe.build
sim-slave-instance-list = {{ dumps(sim_slave_instance_list) }}
ipv4-network = {{ slap_configuration.get('tun-ipv4-network', '') }}
init =
import netaddr
import json
network = netaddr.IPNetwork(options['ipv4-network'])
slave_list = options['sim-slave-instance-list']
# if we don't have enough IPv4 addresses in the network, don't force it
# should we make a promise fail ?
if len(slave_list) + 2 > network.size:
for s in slave_list:
options[s['slave_reference']] = "Too many SIM for the IPv4 network"
else:
# calculate the IP addresses of each SIM
sim_list = []
first_addr = netaddr.IPAddress(network.first)
for i, s in enumerate(sorted(slave_list, key=lambda x: json.loads(x['_'])['imsi'])):
ip = str(first_addr + 2 + i)
options[s['slave_reference']] = ip
slave_parameters = json.loads(s['_'])
slave_parameters['ip'] = ip
s['_'] = json.dumps(slave_parameters)
options['sim-with-ip-list'] = slave_list
{%- for slave in dns_slave_instance_list %}
{%- set slave_parameters = json_module.loads(slave['_']) %}
{% set slave_reference = slave.get('slave_reference', '') %}
{% set publish_section_title = 'publish-%s' % slave_reference %}
{% do part_list.append(publish_section_title) %}
[{{ publish_section_title }}]
recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ slave_reference }}
domain = {{ slave_parameters['subdomain'] }}.{{ slapparameter_dict.get('local_domain', '') }}
ip = {{ slave_parameters.get('ip', '') }}
info = DNS entry with has been attached to service ${slap-configuration:instance-title}.
{%- endfor %}
[buildout]
parts =
directory
mme-config
mme-service
monitor-base
check-interface-up.py
publish-connection-information
{% if slapparameter_dict.get("iperf3", None) %}
iperf-service
iperf-listen-promise
{% endif %}
{% if slapparameter_dict.get("local_domain", '') %}
dnsmasq-service
{% endif %}
{% for part in part_list -%}
{{ ' %s' % part }}
{% endfor %}
extends = {{ monitor_template }}
eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true
[slap-configuration]
recipe = slapos.cookbook:slapconfiguration.serialised
computer = {{ slap_connection['computer-id'] }}
partition = {{ slap_connection['partition-id'] }}
url = {{ slap_connection['server-url'] }}
key = {{ slap_connection['key-file'] }}
cert = {{ slap_connection['cert-file'] }}
configuration.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}
{%- else %}
sim_list = {{ dumps(sim_slave_instance_list) }}
{%- endif %}
[monitor-httpd-conf-parameter]
httpd-include-file = {{ buildout_directory }}/etc/httpd-include-file.conf
port = ${monitor-instance-parameter:monitor-httpd-port}
url = https://[${monitor-instance-parameter:monitor-httpd-ipv6}]:${:port}
[monitor-instance-parameter]
monitor-httpd-port = ${monitor-address:port}
[monitor-address]
recipe = slapos.cookbook:free_port
minimum = 8035
maximum = 8055
ip = ${monitor-instance-parameter:monitor-httpd-ipv6}
[directory]
recipe = slapos.cookbook:mkdirectory
software = {{ buildout_directory }}
home = ${buildout:directory}
etc = ${:home}/etc
var = ${:home}/var
bin = ${:home}/bin
tmp = ${:home}/tmp
run = ${:var}/run
script = ${:etc}/run
service = ${:etc}/service
promise = ${:etc}/promise
log = ${:var}/log
{% if slapparameter_dict.get("mme_config_link", None) %}
[mme-config-dl]
recipe = slapos.recipe.build:download
url = {{ slapparameter_dict.get("mme_config_link") }}
version = {{ slapparameter_dict.get("mme_config_version") }}
offline = false
{% endif %}
### IMS
[ims-service]
recipe = slapos.cookbook:wrapper
command-line = {{ mme }}/lteims ${directory:etc}/ims.cfg
wrapper-path = ${directory:service}/ims
mode = 0775
pidfile = ${directory:run}/ims.pid
hash-files =
${ims-config:output}
${ue-db-config:output}
environment = AMARISOFT_PATH=/opt/amarisoft/.amarisoft
[mme-sh-wrapper]
recipe = slapos.recipe.template
output = ${directory:bin}/${:_buildout_section_name_}
mme-log = ${directory:log}/mme-output.log
inline =
#!/bin/sh
{% if not slapparameter_dict.get("testing", False) %}
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 %}
### MME
[mme-service]
recipe = slapos.cookbook:wrapper
# When the machine shutdowns abruptly, lte_ue is not cleaned up which causes
# amarisoft ltemme to fail. TODO: find a cleaner way to handle this
command-line = ${mme-sh-wrapper:output}
wrapper-path = ${directory:service}/mme
mode = 0775
pidfile = ${directory:run}/mme.pid
hash-files =
${mme-config:output}
${ue-db-config:output}
${mme-sh-wrapper:output}
environment =
LD_LIBRARY_PATH={{ openssl_location }}/lib:{{ nghttp2_location }}/lib
AMARISOFT_PATH=/opt/amarisoft/.amarisoft
### EMPTY mme-ifup script
[mme-ifup-empty]
recipe = slapos.cookbook:wrapper
wrapper-path = ${directory:bin}/mme-ifup-empty
command-line = echo Using interface
mode = 775
{% if slapparameter_dict.get("iperf3", None) %}
### iperf3
[iperf-service]
recipe = slapos.cookbook:wrapper
port = 5001
ip = ${slap-configuration:tun-ipv4-addr}
command-line = {{ iperf3_location }}/bin/iperf3 --server --interval 1 --port ${:port} --bind ${:ip}
wrapper-path = ${directory:service}/iperf3
mode = 0775
pidfile = ${directory:run}/iperf3.pid
[iperf-listen-promise]
<= monitor-promise-base
promise = check_socket_listening
name = iperf3-port-listening.py
config-host = ${iperf-service:ip}
config-port = ${iperf-service:port}
{% endif %}
[config-base]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
context =
section directory directory
section slap_configuration slap-configuration
key slapparameter_dict slap-configuration:configuration
raw gtp_addr_v6 {{ my_ipv6 }}
raw gtp_addr_v4 {{ lan_ipv4 }}
import netaddr netaddr
key ifup_empty mme-ifup-empty:wrapper-path
[ims-config]
<= config-base
url = {{ ims_template }}
output = ${directory:etc}/ims.cfg
[ue-db-config]
<= config-base
url = {{ ue_db_template }}
output = ${directory:etc}/ue_db.cfg
context =
section slap_configuration slap-configuration
import json_module json
[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
{% if slapparameter_dict.get("local_domain", '') %}
[dnsmasq-config]
recipe = slapos.recipe.template:jinja2
url = {{dnsmasq_template}}
filename = dnsmasq.cfg
extensions = jinja2.ext.do
output = ${directory:etc}/${:filename}
context =
import json_module json
import netaddr netaddr
section directory directory
section slap_configuration slap-configuration
key slapparameter_dict slap-configuration:configuration
[dnsmasq-service]
recipe = slapos.cookbook:wrapper
port = 5353
ip = ${slap-configuration:tun-ipv4-addr}
command-line = {{ dnsmasq_location }}/sbin/dnsmasq --conf-file=${dnsmasq-config:output} -x ${directory:run}/dnsmasq.pid --local-service --keep-in-foreground
wrapper-path = ${directory:service}/dnsmasq
mode = 0775
hash-files =
${dnsmasq-config:output}
#[dnsmasq-listen-promise]
#<= monitor-promise-base
#promise = check_socket_listening
#name = dnsmasq-port-listening.py
#config-host = ${dnsmasq-service:ip}
#config-port = ${dnsmasq-service:port}
{% endif %}
[monitor-instance-parameter]
{% if slapparameter_dict.get("name", None) %}
monitor-title = {{ slapparameter_dict['name'] | string }}
{% endif %}
{% if slapparameter_dict.get("monitor-password", None) %}
password = {{ slapparameter_dict['monitor-password'] | string }}
{% endif %}
[publish-connection-information]
<= monitor-publish
recipe = slapos.cookbook:publish.serialised
core-network-ipv6 = {{ my_ipv6 }}
core-network-ipv4 = {{ lan_ipv4 }}
amarisoft-version = {{ lte_version }}
license-expiration = {{ lte_expiration }}
monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html
[macro.promise]
<= monitor-promise-base
name = ${:_buildout_section_name_}
[check-interface-up.py]
<= macro.promise
promise = check_interface_up
config-testing = {{ slapparameter_dict.get("testing", False) }}
{% if not slapparameter_dict.get("testing", False) %}
config-ifname = ${slap-configuration:tun-name}
{% else %}
config-ifname =
{% endif %}
......@@ -30,6 +30,27 @@
"title": "MME Address",
"description": "IP address (and optional port) of S1AP SCTP connection to the MME. The default port is 36412.",
"type": "string"
},
"qci_dscp_mapping":{
"title": "QCI DSCP Mapping",
"description": "Optional array of objects. Allows to define a specific IP differentiated services code point for a given QCI. QCI not explicitly configured use the default DSCP value 0.",
"type": "array",
"items": {
"title": "QCI DSCP Mapping",
"type":"object",
"properties": {
"qci": {
"title": "QCI",
"description": "Integer (range 1 to 254). QCI value.",
"type":"integer"
},
"dscp": {
"title": "DSCP",
"description": "Integer (range 0 to 63). DSCP value.",
"type":"integer"
}
}
}
}
},
"type": "object"
......@@ -37,6 +58,15 @@
},
"type": "object"
},
"x2_peers": {
"title": "X2 Peers",
"description": "Optional array of strings. IP addresses and optional port of other eNodeBs to establish X2 connections. The default port is 36422.",
"type": "array",
"items": {
"title": "X2 Peers",
"type": "string"
}
},
"plmn_list": {
"title": "PLMN list (4G)",
"description": "List of PLMNs broadcasted by the eNodeB, at most 6. (must be set if there are LTE cells)",
......
# instance-enb implements eNB/gNB service.
{#- defaults for global eNB/gNB parameters.
TODO automatically load enb defaults from JSON schema #}
{%- set enb_defaults = {
'com_ws_port': 9001,
'com_addr': '127.0.1.2',
'use_ipv4': False,
'gnb_id_bits': 28,
'nssai': {'1': {'sst': 1}},
} %}
{%- set gtp_addr_lo = '127.0.1.1' %}
{%- for k,v in enb_defaults|dictsort %}
{%- do slapparameter_dict.setdefault(k, v) %}
{%- endfor %}
[buildout]
parts =
directory
enb-config
enb-service
xamari-xlog-service
{% if slapparameter_dict.get('xlog_fluentbit_forward_host') %}
xlog-fluentbit-service
{% endif %}
check-baseband-latency.py
monitor-base
publish-connection-information
extends = {{ monitor_template }}
eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true
{%- set icell_kind='enb' %}
{%- import 'slaplte.jinja2' as slaplte with context %}
{%- import 'ru_libinstance.jinja2.cfg' as rulib with context %}
{%- set ipeer_dict = {} %}
{%- set ipeercell_dict = {} %}
{%- do slaplte.load_ipeer(ipeer_dict) %}
{%- do slaplte.load_ipeercell(ipeercell_dict) %}
{%- do slaplte.check_loaded_everything() %}
{{ rulib.buildout() }}
[myslap]
# NOTE we don't query slapos.cookbook:slapconfiguration the second time because
# slapparameter_dict is potentially modified with defaults.
parameter_dict = {{ dumps(slapparameter_dict) }}
configuration = {{ dumps(slap_configuration) }}
[monitor-httpd-conf-parameter]
httpd-include-file = {{ buildout_directory }}/etc/httpd-include-file.conf
port = ${monitor-instance-parameter:monitor-httpd-port}
url = https://[${monitor-instance-parameter:monitor-httpd-ipv6}]:${:port}
[monitor-instance-parameter]
monitor-httpd-port = ${monitor-address:port}
[monitor-address]
recipe = slapos.cookbook:free_port
minimum = 8035
maximum = 8055
ip = ${monitor-instance-parameter:monitor-httpd-ipv6}
[directory]
recipe = slapos.cookbook:mkdirectory
software = {{ buildout_directory }}
home = ${buildout:directory}
var = ${:home}/var
etc = ${:home}/etc
bin = ${:home}/bin
tmp = ${:home}/tmp
run = ${:var}/run
script = ${:etc}/run
service = ${:etc}/service
promise = ${:etc}/promise
log = ${:var}/log
{% 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
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};
{% endif %}
[enb-service]
recipe = slapos.cookbook:wrapper
command-line = ${enb-sh-wrapper:output}
wrapper-path = ${directory:service}/enb
mode = 0775
reserve-cpu = True
pidfile = ${directory:run}/enb.pid
hash-files =
${enb-config:output}
${enb-sh-wrapper:output}
environment =
LD_LIBRARY_PATH={{ openssl_location }}/lib
AMARISOFT_PATH=/opt/amarisoft/.amarisoft
[xamari-xlog-script]
recipe = slapos.recipe.template
output = ${directory:bin}/${:_buildout_section_name_}
period = {{ slapparameter_dict.get("enb_stats_fetch_period", 60) }}
stats_logspec = stats[samples,rf]/${:period}s
{%- if slapparameter_dict.get("enb_drb_stats_enabled", True) %}
drb_stats_logspec = x.drb_stats/${:period}s
{%- else %}
drb_stats_logspec =
{%- endif %}
rotatespec = 100MB.9
logspec = ${:stats_logspec} ${:drb_stats_logspec}
{%- if slapparameter_dict.get("websocket_password", "") %}
websock = ws://[{{my_ipv6}}]:9001
{%- else %}
websock = ws://127.0.1.2:9001
{%- endif %}
xamari = {{ buildout_directory }}/bin/xamari
logfile = ${monitor-directory:public}/enb.xlog
inline =
#!/bin/sh
exec ${:xamari} xlog --rotate ${:rotatespec} ${:websock} ${:logfile} ${:logspec}
[xamari-xlog-service]
recipe = slapos.cookbook:wrapper
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-config]
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-shared-key = {{ slapparameter_dict.get('xlog_fluentbit_forward_shared_key', '') }}
forward-self-hostname = {{ comp_id['comp-id'] }}
inline =
[SERVICE]
flush 5
[INPUT]
name tail
path ${:logfile}
Read_from_Head True
[OUTPUT]
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 %}
Self_Hostname ${:forward-self-hostname}
tls on
tls.verify off
[xlog-fluentbit-service]
recipe = slapos.cookbook:wrapper
fluentbit = {{ fluent_bit_location }}/bin/fluent-bit
fluentbit-config = ${xlog-fluentbit-config:output}
command-line = ${:fluentbit} -c ${:fluentbit-config}
wrapper-path = ${directory:service}/${:_buildout_section_name_}
hash-files = ${:fluentbit-config}
{% endif %}
[config-base]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
extra-context =
context =
json ors false
section directory directory
key slap_configuration myslap:configuration
key slapparameter_dict myslap:parameter_dict
raw gtp_addr_v6 {{ my_ipv6 }}
raw gtp_addr_v4 {{ lan_ipv4 }}
raw gtp_addr_lo {{ gtp_addr_lo }}
import xbuildout xbuildout
import netaddr netaddr
${:extra-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 }}
extra-context =
import json_module json
key iru_dict :iru_dict
key icell_dict :icell_dict
key ipeer_dict :ipeer_dict
key ipeercell_dict :ipeercell_dict
iru_dict = {{ dumps(rulib.iru_dict) }}
icell_dict = {{ dumps(rulib.icell_dict) }}
ipeer_dict = {{ dumps(ipeer_dict) }}
ipeercell_dict = {{ dumps(ipeercell_dict) }}
[publish-connection-information]
<= monitor-publish
recipe = slapos.cookbook:publish.serialised
{%- if slapparameter_dict.get("websocket_password", "") %}
websocket_url = ws://[{{my_ipv6}}]:9001
{%- endif %}
enb-ipv6 = {{ my_ipv6 }}
enb-ipv4 = {{ lan_ipv4 }}
amarisoft-version = {{ lte_version }}
license-expiration = {{ lte_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) }}
peer-list = {{ dumps(ipeer_dict.keys() | sort) }}
peer-cell-list = {{ dumps(ipeercell_dict.keys() | sort) }}
[monitor-instance-parameter]
{% if slapparameter_dict.get("name", None) %}
monitor-title = {{ slapparameter_dict['name'] | string }}
{% endif %}
{% if slapparameter_dict.get("monitor-password", None) %}
password = {{ slapparameter_dict['monitor-password'] | string }}
{% endif %}
[macro.promise]
<= monitor-promise-base
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) }}
{% set obsolete_message = "This software type doesn't exist anymore. Please ask Rapid.Space team to switch your services to the correct software types (gNB, eNB and Core Network)" -%}
{% set part_list = [] -%}
{%- for i, slave in enumerate(slave_instance_list) %}
{% set slave_reference = slave.get('slave_reference', '') %}
{% set publish_section_title = 'publish-%s' % slave_reference %}
{% do part_list.append(publish_section_title) %}
[{{ publish_section_title }}]
recipe = slapos.cookbook:publish.serialised
-slave-reference = {{ slave_reference }}
info = {{ obsolete_message }}
{%- endfor %}
[buildout]
parts =
publish-connection-information
{% for part in part_list -%}
{{ ' %s' % part }}
{% endfor %}
eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true
[publish-connection-information]
recipe = slapos.cookbook:publish.serialised
message = {{ obsolete_message }}
# instance-ors-enb translates ORS enb/gnb into generic enb with 1 SDR RU and 1 CELL.
{#- enb_mode indicates with which mode ors' enb is instantiated with - enb | gnb #}
{%- set enb_mode = slap_configuration['slap-software-type'] %}
{%- do assert(enb_mode in ('enb', 'gnb'), enb_mode) %}
{#- defaults for ORS parameters.
TODO automatically load ORS/enb and ORS/gnb defaults from JSON schema #}
{%- set ors_enb_defaults = {
"bandwidth": "20 MHz",
"n_antenna_dl": 2,
"n_antenna_ul": 2,
"rf_mode": "tdd",
"tdd_ul_dl_config": "[Configuration 2] 5ms 2UL 6DL (default)",
"pci": 1,
"cell_id": "0x01",
"tac": "0x0001",
"root_sequence_index": 204,
"enb_id": "0x1A2D0",
"mme_list": {'1': {'mme_addr': '127.0.1.100'}},
"plmn_list": {"1": {'plmn': '00101'}},
"ncell_list": {},
"x2_peers": {},
"inactivity_timer": 10000,
"disable_sdr": false
} %}
{%- set ors_gnb_defaults = {
"nr_bandwidth": 40,
"n_antenna_dl": 2,
"n_antenna_ul": 2,
"rf_mode": "tdd",
"tdd_ul_dl_config": "5ms 2UL 7DL 4/6 (default)",
"ssb_pos_bitmap": "10000000",
"pci": 500,
"cell_id": "0x01",
"gnb_id": "0x12345",
"gnb_id_bits": 28,
"amf_list": {'1': {'amf_addr': '127.0.1.100'}},
"plmn_list": {'1': {'plmn': '00101', 'tac': 100}},
"ncell_list": {},
"xn_peers": {},
"inactivity_timer": 10000,
"disable_sdr": false
} %}
{%- set ors_defaults = {'enb': ors_enb_defaults, 'gnb': ors_gnb_defaults} [enb_mode] %}
{%- 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 %}
{%- endfor %}
{#- inject ru+cell synthesized from ORS-specific parameters #}
{%- macro iref(name) %}
{{- '%s.%s' % (slap_configuration['instance-title'], name) -}}
{%- endmacro %}
{%- do ishared_list.append({
'slave_title': iref('RU'),
'slave_reference': False,
'_': {
'ru_type': 'sdr',
'ru_link_type': 'sdr',
'sdr_dev_list': [0],
'n_antenna_dl': slapparameter_dict.n_antenna_dl,
'n_antenna_ul': slapparameter_dict.n_antenna_ul,
'tx_gain': ors_version['current-tx-gain'],
'rx_gain': ors_version['current-rx-gain'],
'txrx_active': 'ACTIVE' if (not slapparameter_dict.disable_sdr) else 'INACTIVE',
} |tojson
})
%}
{%- if enb_mode == 'enb' %}
{%- set cell = {
'cell_type': 'lte',
'dl_earfcn': ors_version['current-earfcn'],
'bandwidth': float(slapparameter_dict.bandwidth.removesuffix(' MHz')),
'tac': slapparameter_dict.tac,
'root_sequence_index': slapparameter_dict.root_sequence_index,
}
%}
{%- elif enb_mode == 'gnb' %}
{%- set cell = {
'cell_type': 'nr',
'dl_nr_arfcn': ors_version['current-nr-arfcn'],
'nr_band': ors_version['current-nr-band'],
'bandwidth': slapparameter_dict.nr_bandwidth,
'ssb_pos_bitmap': slapparameter_dict.ssb_pos_bitmap,
'root_sequence_index': 1,
}
%}
{%- endif %}
{%- do cell.update({
'cell_kind': 'enb',
'rf_mode': slapparameter_dict.rf_mode,
'pci': slapparameter_dict.pci,
'cell_id': slapparameter_dict.cell_id,
'tdd_ul_dl_config': slapparameter_dict.tdd_ul_dl_config,
'inactivity_timer': slapparameter_dict.inactivity_timer,
'ru': { 'ru_type': 'ru_ref',
'ru_ref': iref('RU') }
})
%}
{%- do ishared_list.append({
'slave_title': iref('CELL'),
'slave_reference': False,
'_': cell | tojson
})
%}
{#- inject synthesized peer cells #}
{%- for k, ncell in slapparameter_dict.ncell_list|dictsort %}
{%- set peercell = {'cell_kind': 'enb_peer'} %}
{%- macro _(name, default) %}
{%- if default is defined %}
{%- do peercell.update({name: default}) %}
{%- endif %}
{%- if name in ncell %}
{%- do peercell.update({name: ncell[name]}) %}
{%- endif %}
{%- endmacro %}
{%- if enb_mode == 'enb' %}
{%- do peercell.update({'cell_type': 'lte'}) %}
{%- if 'cell_id' in ncell %}
{%- do peercell.update({'e_cell_id': ncell.cell_id}) %}
{%- endif %}
{%- do _('pci') %}
{%- do _('dl_earfcn') %}
{%- do _('tac', '0x0001') %}
{%- elif enb_mode == 'gnb' %}
{%- do peercell.update({'cell_type': 'nr'}) %}
{%- do _('nr_cell_id') %}
{%- do _('gnb_id_bits') %}
{%- do _('pci') %}
{%- do _('dl_nr_arfcn') %}
{%- do _('ssb_nr_arfcn') %}
{%- do _('tac', 1) %}
{%- do _('nr_band') %}
{%- endif %}
{%- do ishared_list.append({
'slave_title': '%s%s' % (iref('PEERCELL'), k),
'slave_reference': False,
'_': peercell | tojson
})
%}
{%- endfor %}
{#- inject synthesized peers #}
{%- if enb_mode == 'lte' %}
{%- for k, peer in slapparameter_dict.x2_peers|dictsort %}
{%- do ishared_list.append({
'slave_title': '%s%s' % (iref('X2_PEER'), k),
'slave_reference': False,
'_': {
'peer_type': 'nr',
'x2_addr': peer.x2_addr,
} | tojson
})
%}
{%- endfor %}
{%- elif enb_mode == 'nr' %}
{%- for k, peer in slapparameter_dict.xn_peers|dictsort %}
{%- do ishared_list.append({
'slave_title': '%s%s' % (iref('XN_PEER'), k),
'slave_reference': False,
'_': {
'peer_type': 'nr',
'xn_addr': peer.xn_addr
} | tojson
})
%}
{%- endfor %}
{%- endif %}
{#- gnb: plmn_list -> plmn_list_5g #}
{%- if enb_mode == 'gnb' %}
{%- set _ = slapparameter_dict %}
{%- do _.update({'plmn_list_5g': _.plmn_list}) %}
{%- do _.pop('plmn_list') %}
{%- endif %}
{#- backward compatibility: if ORS is running in gnb mode, and gnb_* parameters
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 %}
{%- if 'gnb_drb_stats_enabled' in _ %}
{%- do _.update({'enb_drb_stats_enabled': _.gnb_drb_stats_enabled}) %}
{%- endif %}
{%- endif %}
# code of generic enb
{% include 'instance-enb-base.jinja2.cfg' %}
# let all templates know we are running in ORS mode
[config-base]
context -=
json ors false
context +=
key ors :ors
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'] }}
{%- if enb_mode == 'enb' %}
current-earfcn = {{ ors_version['current-earfcn'] }}
{%- elif enb_mode == 'gnb' %}
current-nr-arfcn = {{ ors_version['current-nr-arfcn'] }}
current-nr-band = {{ ors_version['current-nr-band'] }}
{%- endif %}
# hide ru-list, cell-list, peer-list and peer-cell-list from published information
[publish-connection-information]
depends += ${publish-connection-information-ors-cleanup:recipe}
[publish-connection-information-ors-cleanup]
recipe = slapos.recipe.build
init =
publish = self.buildout['publish-connection-information']
del publish['ru-list']
del publish['cell-list']
del publish['peer-list']
del publish['peer-cell-list']
[buildout]
extends =
${template:output}
[switch-softwaretype]
enb = dynamic-template-ors-enb:output
gnb = dynamic-template-ors-enb:output
obsolete = dynamic-template-obsolete:output
enb-epc = $${:obsolete}
gnb-epc = $${:obsolete}
epc = $${:obsolete}
mme = $${:obsolete}
ue =
[dynamic-template-obsolete]
< = jinja2-template-base
url = ${template-obsolete:target}
filename = instance-obsolete.cfg
extensions = jinja2.ext.do
extra-context =
key slave_instance_list slap-configuration:slave-instance-list
# ORS-specific enb and gnb
# both are served by instance-ors-enb, which translates
# ORS enb/gnb schemas to generic enb with only one RU and one LTE or NR CELL
[dynamic-template-ors-enb]
< = dynamic-template-enb
url = ${template-ors-enb:target}
filename = instance-enb.cfg
extra-context +=
section ors ors-version
section ors_version ors-version
import-list +=
rawfile instance-enb-base.jinja2.cfg ${template-enb:target}
[ors-version]
recipe = slapos.recipe.build
configuration = $${slap-configuration:configuration}
init =
import subprocess
range_map = {
"B38": "2570MHz - 2620MHz",
"B39": "1880MHz - 1920MHz",
"B42": "3400MHz - 3600MHz",
"B43": "3600MHz - 3800MHz",
"B28": "758MHz - 803MHz",
"N77": "3300MHz - 4200MHz",
"N79": "4400MHz - 5000MHz",
"UNKNOWN": "Information not available for this band",
}
default_tx_gain_map = {
"B38": (59, 65),
"B39": (59, 64),
"B42": (63, 62),
"B43": (63, 62),
"B28": (60, 62),
"N77": (60, 62),
"N79": (60, 62),
"UNKNOWN": (60, 62),
}
default_rx_gain_map = {
"B38": (43, 43),
"B39": (43, 43),
"B42": (43, 43),
"B43": (43, 43),
"B28": (43, 43),
"N77": (43, 43),
"N79": (43, 43),
"UNKNOWN": (43, 43),
}
default_earfcn_map = {
"B38": 38050,
"B39": 38350,
"B42": 42590,
"B43": 44590,
"B28": 9550,
"N77": 0,
"N79": 0,
"UNKNOWN": 0,
}
default_nr_arfcn_map = {
"B38": 519000,
"B39": 378000,
"B42": 632628,
"B43": 646666,
"B28": 0,
"N77": 660000,
"N79": 720000,
"UNKNOWN": 0,
}
default_nr_band_map = {
"B38": 41,
"B39": 39,
"B42": 78,
"B43": 78,
"B28": 0,
"N77": 77,
"N79": 79,
"UNKNOWN": 0,
}
power_map = {
"B38": (
lambda x: (-0.008712931375092506) * x**2 + (2.1973585140044642) * x + (-94.29420762479742),
lambda x: (-0.004472751640641793) * x**2 + (1.6308290630103919) * x + (-81.84549245154561),
),
"B39": (
lambda x: (-0.008712931375092506) * x**2 + (2.1973585140044642) * x + (-94.29420762479742),
lambda x: (-0.0022523817802900985) * x**2 + (1.2674016231310092) * x + (-66.57165215468584),
),
"B42": (
lambda x: (-0.014198126839751619) * x**2 + (2.980758813262773) * x + (-125.25800492285738),
lambda x: (0.003977721774394756) * x**2 + (0.527208191717173) * x + (-42.761142655285376),
),
"B43": (
lambda x: (-0.014198126839751619) * x**2 + (2.980758813262773) * x + (-125.25800492285738),
lambda x: (-0.0036530114002551943) * x**2 + (1.510856844601873) * x + (-74.58790185136355),
),
"B28": (
lambda x: "UNKNOWN",
lambda x: "UNKNOWN",
),
"N77": (
lambda x: "UNKNOWN",
lambda x: "UNKNOWN",
),
"N79": (
lambda x: "UNKNOWN",
lambda x: "UNKNOWN",
),
"UNKNOWN": (
lambda x: "UNKNOWN",
lambda x: "UNKNOWN",
),
}
def get_sdr_info(cmd):
if options['configuration'].get('testing', False):
return {'t': 'TDD', 'b': 'B39', 'v': '4.2', 's': 'B53'}[cmd].encode()
return subprocess.check_output(
["sudo", "-n", "/opt/amarisoft/get-sdr-info", "-" + cmd]
)
version = get_sdr_info('v').decode()
options['version'] = float(version) if version != 'UNKNOWN' else 0
options['band'] = get_sdr_info('b').decode()
options['tdd'] = get_sdr_info('t').decode()
options['one-watt'] = bool(options['version'] >= 4)
options['ors-version'] = "{} {} {}".format(
options['tdd'],
options['band'],
"2x1W" if options['one-watt'] else "2x0.5W",
)
default_tx_gain = default_tx_gain_map [options['band']][int(options['one-watt'])]
default_rx_gain = default_rx_gain_map [options['band']][int(options['one-watt'])]
default_earfcn = default_earfcn_map [options['band']]
default_nr_arfcn = default_nr_arfcn_map[options['band']]
default_nr_band = default_nr_band_map [options['band']]
options['range'] = range_map [options['band']]
options['current-tx-gain'] = options['configuration'].get('tx_gain' , default_tx_gain )
options['current-rx-gain'] = options['configuration'].get('rx_gain' , default_rx_gain )
options['current-earfcn'] = options['configuration'].get('dl_earfcn' , default_earfcn )
options['current-nr-arfcn'] = options['configuration'].get('dl_nr_arfcn', default_nr_arfcn)
options['current-nr-band'] = options['configuration'].get('nr_band' , default_nr_band )
power_estimate_dbm = power_map[options['band']][int(options['one-watt'])](float(options['current-tx-gain']))
if power_estimate_dbm == "UNKNOWN":
power_estimate = "Information not available for this band"
else:
power_estimate_mw = 10 ** ( power_estimate_dbm / 10 )
if power_estimate_mw < 0.01:
power_estimate_s = "{:0.2f} µW".format(power_estimate_mw * 1000)
else:
power_estimate_s = "{:0.2f} mW".format(power_estimate_mw)
power_estimate = "{:0.2f} dBm ({})".format(power_estimate_dbm, power_estimate_s)
options['power-estimate'] = power_estimate
# instance-ue implements UEsim service.
[buildout]
parts =
directory
lte-ue-config
lte-ue-service
monitor-base
publish-connection-information
extends = {{ monitor_template }}
eggs-directory = {{ eggs_directory }}
develop-eggs-directory = {{ develop_eggs_directory }}
offline = true
{%- set icell_kind='ue' %}
{%- import 'slaplte.jinja2' as slaplte with context %}
{%- import 'ru_libinstance.jinja2.cfg' as rulib with context %}
{%- set iue_dict = {} %}
{%- do slaplte.load_iue(iue_dict) %}
{%- do slaplte.check_loaded_everything() %}
{{ rulib.buildout() }}
[myslap]
# see instance-enb.jinja2.cfg about myslap
parameter_dict = {{ dumps(slapparameter_dict) }}
configuration = {{ dumps(slap_configuration) }}
[monitor-httpd-conf-parameter]
httpd-include-file = {{ buildout_directory }}/etc/httpd-include-file.conf
port = ${monitor-instance-parameter:monitor-httpd-port}
url = https://[${monitor-instance-parameter:monitor-httpd-ipv6}]:${:port}
[monitor-instance-parameter]
monitor-httpd-port = ${monitor-address:port}
[monitor-address]
recipe = slapos.cookbook:free_port
minimum = 8035
maximum = 8055
ip = ${monitor-instance-parameter:monitor-httpd-ipv6}
[directory]
recipe = slapos.cookbook:mkdirectory
software = {{ buildout_directory }}
home = ${buildout:directory}
etc = ${:home}/etc
var = ${:home}/var
etc = ${:home}/etc
bin = ${:home}/bin
tmp = ${:home}/tmp
run = ${:var}/run
script = ${:etc}/run
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
inline =
#!/bin/sh
{% if not slapparameter_dict.get("testing", False) %}
sudo /opt/amarisoft/rm-tmp-lte | true;
(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};
{{ ue }}/lteue ${directory:etc}/ue.cfg >> ${:ue-log} 2>> ${:ue-log};
{% endif %}
### User Equipment (UE)
[lte-ue-service]
recipe = slapos.cookbook:wrapper
command-line = ${lte-ue-sh-wrapper:output}
wrapper-path = ${directory:service}/lte-ue
mode = 0775
reserve-cpu = True
pidfile = ${directory:run}/ue.pid
hash-files =
${lte-ue-config:output}
${lte-ue-sh-wrapper:output}
environment =
LD_LIBRARY_PATH={{ openssl_location }}/lib
AMARISOFT_PATH=/opt/amarisoft/.amarisoft
[config-base]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
extra-context =
context =
json ors false
section directory directory
section pub_info publish-connection-information
key slap_configuration myslap:configuration
key slapparameter_dict myslap:parameter_dict
import xbuildout xbuildout
${:extra-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 }}
extra-context =
import json_module json
key iru_dict :iru_dict
key icell_dict :icell_dict
key iue_dict :iue_dict
iru_dict = {{ dumps(rulib.iru_dict) }}
icell_dict = {{ dumps(rulib.icell_dict) }}
iue_dict = {{ dumps(iue_dict) }}
[publish-connection-information]
<= monitor-publish
recipe = slapos.cookbook:publish.serialised
rue_bind_addr = {{my_ipv6}}
com_addr = [{{my_ipv6}}]:9002
monitor-gadget-url = ${:monitor-base-url}/gadget/software.cfg.html
[monitor-instance-parameter]
{% if slapparameter_dict.get("name", None) %}
monitor-title = {{ slapparameter_dict['name'] | string }}
{% endif %}
{% if slapparameter_dict.get("monitor-password", None) %}
password = {{ slapparameter_dict['monitor-password'] | string }}
{% endif %}
[buildout]
parts =
switch-softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[directory]
recipe = slapos.cookbook:mkdirectory
software = ${buildout:directory}
home = $${buildout:directory}
etc = $${:home}/etc
[slap-configuration]
recipe = slapos.cookbook:slapconfiguration.serialised
computer = $${slap-connection:computer-id}
partition = $${slap-connection:partition-id}
url = $${slap-connection:server-url}
key = $${slap-connection:key-file}
cert = $${slap-connection:cert-file}
[jinja2-template-base]
recipe = slapos.recipe.template:jinja2
output = $${buildout:directory}/$${:filename}
extra-context =
depends = $${activate-eggs:recipe}
context =
import xbuildout xbuildout
import json_module json
import netaddr netaddr
import nrarfcn_module nrarfcn
import xearfcn_module xlte.earfcn
import xnrarfcn_module xlte.nrarfcn
key eggs_directory buildout:eggs-directory
key develop_eggs_directory buildout:develop-eggs-directory
raw buildout_directory ${buildout:directory}
section directory directory
raw pythonwitheggs ${buildout:bin-directory}/pythonwitheggs
section slap_connection slap-connection
key slapparameter_dict slap-configuration:configuration
key lan_ipv4 lan-ip:ipv4
key my_ipv6 slap-configuration:ipv6-random
$${:extra-context}
import-list =
rawfile slaplte.jinja2 ${slaplte.jinja2:target}
rawfile ru_libinstance.jinja2.cfg ${ru_libinstance.jinja2.cfg:target}
rawfile ru_sdr_libinstance.jinja2.cfg ${ru_sdr_libinstance.jinja2.cfg:target}
rawfile ru_lopcomm_libinstance.jinja2.cfg ${ru_lopcomm_libinstance.jinja2.cfg:target}
rawfile ru_sunwave_libinstance.jinja2.cfg ${ru_sunwave_libinstance.jinja2.cfg:target}
# activate eggs and modules used in jinja2 templates
[activate-eggs]
recipe = slapos.recipe.build
init =
import pkg_resources as rpkg
buildout = self.buildout['buildout']
env = rpkg.Environment([buildout['develop-eggs-directory'],
buildout['eggs-directory']])
env.scan()
def activate(pkgspec):
req = rpkg.Requirement.parse(pkgspec)
for dist in rpkg.working_set.resolve([req], env):
rpkg.working_set.add(dist)
activate('xlte')
activate('nrarfcn')
# ~ import xbuildout
import sys, types
def readfile(path):
with open(path) as f:
return f.read()
xbuildout = types.ModuleType('xbuildout')
exec(readfile('${ru_xbuildout.py:target}'), xbuildout.__dict__)
assert 'xbuildout' not in sys.modules
sys.modules['xbuildout'] = xbuildout
[amarisoft]
recipe = slapos.recipe.build
init =
import os, re
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 + "/ims"
options['ue'] = path + "/ue"
import os
lte_expiration = "Unknown"
amarisoft_dir = '/opt/amarisoft/.amarisoft'
try:
for filename in os.listdir(amarisoft_dir):
if filename.endswith('.key'):
with open(os.path.join(amarisoft_dir, filename), 'r') as f:
f.seek(260)
for l in f:
if l.startswith('version='):
lte_expiration = l.split('=')[1].strip()
except FileNotFoundError:
pass
options['lte-expiration'] = lte_expiration
[lan-ip]
recipe = slapos.recipe.build
init =
import netifaces
for i in netifaces.interfaces():
if not (i.startswith("slaptun") or i.startswith("slaptap") or i.startswith("re6stnet") or i == "lo"):
a = netifaces.ifaddresses(i)
if netifaces.AF_INET in a:
try:
options['ipv4'] = a[netifaces.AF_INET][0]['addr']
except:
options['ipv4'] = "0.0.0.0"
[comp-id]
recipe = slapos.recipe.build
computer = $${slap-connection:computer-id}
title = $${slap-configuration:root-instance-title}
init =
import socket
options['hostname'] = socket.gethostname()
comp_id = '__'.join(options[x] for x in ('hostname', 'computer', 'title'))
options['comp-id'] = comp_id
[switch-softwaretype]
recipe = slapos.cookbook:switch-softwaretype
enb = dynamic-template-enb:output
core-network = dynamic-template-core-network:output
ue = dynamic-template-ue:output
RootSoftwareInstance = $${:core-network}
[dynamic-template-enb]
< = jinja2-template-base
url = ${template-enb:target}
filename = instance-enb.cfg
extensions = jinja2.ext.do
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
raw enb_template ${enb.jinja2.cfg:target}
raw slaplte_template ${slaplte.jinja2:target}
raw drb_lte_template ${drb_lte.jinja2.cfg:target}
raw drb_nr_template ${drb_nr.jinja2.cfg:target}
raw sib23_template ${sib23.jinja2.asn:target}
raw ru_amarisoft_stats_template ${ru_amarisoft-stats.jinja2.py:target}
raw ru_amarisoft_rf_info_template ${ru_amarisoft-rf-info.jinja2.py:target}
raw ru_lopcomm_stats_template ${ru_lopcomm_stats.jinja2.py:target}
raw ru_lopcomm_config_template ${ru_lopcomm_config.jinja2.py:target}
raw ru_lopcomm_software_template ${ru_lopcomm_software.jinja2.py:target}
raw ru_lopcomm_reset_info_template ${ru_lopcomm_reset-info.jinja2.py:target}
raw ru_lopcomm_reset_template ${ru_lopcomm_reset.jinja2.py:target}
raw ru_lopcomm_CreateProcessingEle_template ${ru_lopcomm_CreateProcessingEle.jinja2.xml:target}
raw ru_lopcomm_cu_config_template ${ru_lopcomm_cu_config.jinja2.xml:target}
raw ru_lopcomm_cu_inactive_config_template ${ru_lopcomm_cu_inactive_config.jinja2.xml:target}
raw ru_lopcomm_firmware_path ${ru_lopcomm_firmware-dl:target}
raw ru_lopcomm_firmware_filename ${ru_lopcomm_firmware-dl:filename}
raw ru_tapsplit ${ru_tapsplit:target}
raw netcapdo ${netcapdo:exe}
raw openssl_location ${openssl:location}
raw ru_dnsmasq_template ${ru_dnsmasq.jinja2.cfg:target}
raw dnsmasq_location ${dnsmasq:location}
raw fluent_bit_location ${fluent-bit:location}
raw openssh_location ${openssh:location}
raw openssh_output_keygen ${openssh-output:keygen}
[dynamic-template-core-network]
< = jinja2-template-base
url = ${template-core-network:target}
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
raw mme_template ${mme.jinja2.cfg:target}
raw dnsmasq_template ${dnsmasq-core-network.jinja2.cfg:target}
raw ims_template ${ims.jinja2.cfg:target}
raw ue_db_template ${ue_db.jinja2.cfg:target}
raw openssl_location ${openssl:location}
raw nghttp2_location ${nghttp2:location}
raw iperf3_location ${iperf3:location}
raw dnsmasq_location ${dnsmasq:location}
key slave_instance_list slap-configuration:slave-instance-list
section slap_configuration slap-configuration
[dynamic-template-ue]
< = jinja2-template-base
url = ${template-ue:target}
filename = instance-ue.cfg
extensions = jinja2.ext.do
extra-context =
section slap_configuration slap-configuration
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_lopcomm_stats_template ${ru_lopcomm_stats.jinja2.py:target}
raw ru_lopcomm_config_template ${ru_lopcomm_config.jinja2.py:target}
raw ru_lopcomm_software_template ${ru_lopcomm_software.jinja2.py:target}
raw ru_lopcomm_reset_info_template ${ru_lopcomm_reset-info.jinja2.py:target}
raw ru_lopcomm_reset_template ${ru_lopcomm_reset.jinja2.py:target}
raw ru_lopcomm_CreateProcessingEle_template ${ru_lopcomm_CreateProcessingEle.jinja2.xml:target}
raw ru_lopcomm_cu_config_template ${ru_lopcomm_cu_config.jinja2.xml:target}
raw ru_lopcomm_cu_inactive_config_template ${ru_lopcomm_cu_inactive_config.jinja2.xml:target}
raw ru_lopcomm_firmware_path ${ru_lopcomm_firmware-dl:target}
raw ru_lopcomm_firmware_filename ${ru_lopcomm_firmware-dl:filename}
raw ru_tapsplit ${ru_tapsplit:target}
raw netcapdo ${netcapdo:exe}
raw ru_dnsmasq_template ${ru_dnsmasq.jinja2.cfg:target}
raw dnsmasq_location ${dnsmasq:location}
raw openssh_location ${openssh:location}
raw openssh_output_keygen ${openssh-output:keygen}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer Cell. Common properties",
"type": "object",
"required": [
"cell_type",
"cell_kind",
"pci",
"tac"
],
"properties": {
"cell_type": {
"type": "string"
},
"cell_kind": {
"type": "string",
"const": "enb_peer"
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer Cell",
"type": "object",
"oneOf": [
{ "$ref": "../../peer/cell/lte/input-schema.json" },
{ "$ref": "../../peer/cell/nr/input-schema.json" }
]
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "LTE Peer Cell",
"type": "object",
"required": [
"cell_type",
"cell_kind",
"pci",
"tac",
"e_cell_id",
"dl_earfcn"
],
"properties": {
"cell_type": {
"$ref": "../../../peer/cell/common.json#/properties/cell_type",
"const": "lte"
},
"e_cell_id": {
"title": "E-UTRAN Cell ID",
"description": "28 bit E-UTRAN cell identity. Concatenation of enb_id and cell_id of the neighbour cell.",
"type": "string"
},
"dl_earfcn": { "$ref": "../../../cell/lte/input-schema.json#/properties/dl_earfcn" },
"pci": { "$ref": "../../../cell/lte/input-schema.json#/properties/pci" },
"tac": { "$ref": "../../../cell/lte/input-schema.json#/properties/tac" }
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "NR Peer Cell",
"type": "object",
"required": [
"cell_type",
"cell_kind",
"pci",
"tac",
"nr_cell_id",
"gnb_id_bits",
"dl_nr_arfcn",
"nr_band"
],
"properties": {
"cell_type": {
"$ref": "../../../peer/cell/common.json#/properties/cell_type",
"const": "nr"
},
"nr_cell_id": {
"title": "NR Cell ID",
"description": "Concatenation of gnb_id and cell_id of the neighbour cell",
"type": "string"
},
"gnb_id_bits": {
"title": "gNB ID bits",
"description": "Number of bits for the gNodeB global identifier. (range 22 to 32)",
"type": "integer"
},
"dl_nr_arfcn": { "$ref": "../../../cell/nr/input-schema.json#/properties/dl_nr_arfcn" },
"nr_band": { "$ref": "../../../cell/nr/input-schema.json#/properties/nr_band" },
"ssb_nr_arfcn": { "$ref": "../../../cell/nr/input-schema.json#/properties/ssb_nr_arfcn" },
"ul_nr_arfcn": { "$ref": "../../../cell/nr/input-schema.json#/properties/ul_nr_arfcn" },
"pci": { "$ref": "../../../cell/nr/input-schema.json#/properties/pci" },
"tac": { "$ref": "../../../cell/nr/input-schema.json#/$defs/tac" }
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by Peer Cell instantiation (stub)",
"type": "object",
"properties": {}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer. Common properties",
"type": "object",
"required": [
"peer_type"
],
"properties": {
"peer_type": {
"type": "string"
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer eNB/gNB",
"type": "object",
"oneOf": [
{ "$ref": "../peer/lte/input-schema.json" },
{ "$ref": "../peer/nr/input-schema.json" }
]
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer eNB",
"type": "object",
"required": [
"peer_type",
"x2_addr"
],
"properties": {
"peer_type": {
"$ref": "../../peer/common.json#/properties/peer_type",
"const": "lte"
},
"x2_addr": {
"title": "X2 Address",
"description": "X2 Address of the neighbour node (eNB Address)",
"type": "string"
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Peer gNB",
"type": "object",
"required": [
"peer_type",
"xn_addr"
],
"properties": {
"peer_type": {
"$ref": "../../peer/common.json#/properties/peer_type",
"const": "nr"
},
"xn_addr": {
"title": "XN Address",
"description": "XN Address of the neighbour node (gNB Address)",
"type": "string"
}
}
}
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by Peer eNB/gNB instantiation (stub)",
"type": "object",
"properties": {}
}
#!{{ python_path }}
import json
import logging
from logging.handlers import RotatingFileHandler
import time
from websocket import create_connection
class enbWebSocket:
def __init__(self):
log_file = "{{ log_file }}"
self.logger = logging.getLogger('logger')
self.logger.setLevel(logging.INFO)
handler = RotatingFileHandler(log_file, maxBytes=30000, backupCount=2)
formatter = logging.Formatter('{"time": "%(asctime)s", "log_level": "%(levelname)s", "message": "%(message)s", "data": %(data)s}')
handler.setFormatter(formatter)
self.logger.addHandler(handler)
if {{ testing }}:
return
self.ws_url = "ws://127.0.1.2:9001"
self.ws = create_connection(self.ws_url)
def close(self):
if {{ testing }}:
return
self.ws.close()
def send(self, msg):
self.ws.send(json.dumps(msg))
def recv(self, message_type):
for i in range(1,20):
r = json.loads(self.ws.recv())
if r['message'] == message_type:
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.logger.info('RF info', extra={'data': json.dumps(r)})
if __name__ == '__main__':
ws = enbWebSocket()
try:
while True:
ws.stats()
time.sleep({{ stats_period }})
finally:
ws.close()
#!{{ python_path }}
import json
import logging
from logging.handlers import RotatingFileHandler
import time
from websocket import create_connection
class enbWebSocket:
def __init__(self):
log_file = "{{ log_file }}"
self.logger = logging.getLogger('logger')
self.logger.setLevel(logging.INFO)
handler = RotatingFileHandler(log_file, maxBytes=30000, backupCount=2)
formatter = logging.Formatter('{"time": "%(asctime)s", "log_level": "%(levelname)s", "message": "%(message)s", "data": %(data)s}')
handler.setFormatter(formatter)
self.logger.addHandler(handler)
if {{ testing }}:
return
self.ws_url = "ws://127.0.1.2:9001"
self.ws = create_connection(self.ws_url)
def close(self):
if {{ testing }}:
return
self.ws.close()
def send(self, msg):
self.ws.send(json.dumps(msg))
def recv(self, message_type):
for i in range(1,20):
r = json.loads(self.ws.recv())
if r['message'] == message_type:
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.logger.info('Samples stats', extra={'data': json.dumps(r)})
if __name__ == '__main__':
ws = enbWebSocket()
try:
while True:
ws.stats()
time.sleep({{ stats_period }})
finally:
ws.close()
# ru/buildout.cfg provides common software code for handling Radio Units.
[buildout]
extends =
sdr/buildout.cfg
lopcomm/buildout.cfg
sunwave/buildout.cfg
parts +=
netcapdo
setcap-netcapdo
[ru_libinstance.jinja2.cfg]
<= download-base
[ru_dnsmasq.jinja2.cfg]
<= download-base
[ru_tapsplit]
<= download-base
[ru_capdo.c]
<= download-base
[netcapdo]
recipe = plone.recipe.command
exe = ${buildout:directory}/netcapdo
command = gcc ${:ccflags} -o ${:exe} ${ru_capdo.c:target} -lcap
ccflags = -I${libcap:location}/include -L${libcap:location}/lib -Wl,-rpath=${libcap:location}/lib
stop-on-error = true
[setcap-netcapdo]
<= setcap
exe = ${netcapdo:exe}
[ru_amarisoft-stats.jinja2.py]
<= download-base
[ru_amarisoft-rf-info.jinja2.py]
<= download-base
[ru_xbuildout.py]
<= download-base
// Copyright (C) 2023 Nexedi SA and Contributors.
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
// Program `capdo prog ...` executes prog with inherited capabilities.
// It is used as trampoline to run scripts under setcap environment.
//
// TODO Relying on setcap should be removed once SlapOS is improved to provide
// several TAP interfaces to instances. See discussion at
// https://lab.nexedi.com/nexedi/slapos/merge_requests/1471#note_194356
// for details.
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/capability.h>
#include <sys/prctl.h>
static int die(const char *fmt, ...);
static int die_err(const char *msg);
int main(int argc, const char *argv[]) {
cap_t caps;
cap_value_t cap;
cap_flag_value_t flag;
uint64_t capbits = 0;
if (argc < 2)
die("usage: capdo prog arguments...");
// permitted -> inheritable (so that we can raise ambient below)
caps = cap_get_proc();
if (!caps)
die("cap_get_proc failed");
for (cap = 0; cap < CAP_LAST_CAP; cap++) {
if (cap_get_flag(caps, cap, CAP_PERMITTED, &flag)) {
if (errno = EINVAL)
continue; // this cap is not supported by running kernel
die_err("cap_get_flag");
}
if (flag) {
cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, flag) && die_err("cap_set_flag");
capbits |= (1ULL << cap);
}
}
cap_set_proc(caps) && die_err("cap_set_proc");
// raise ambient capabilities to what is permitted/inheritable
// this way executed program will have the same capabilities that we have
for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
if (capbits & (1ULL << cap))
prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) && die_err("prctl ambient raise");
}
// tail to exec target
argv++;
execv(argv[0], argv);
// the only chance we are here is due to exec error
die_err(argv[0]);
}
static int die(const char* fmt, ...) {
va_list ap;
fprintf(stderr, "E: capdo: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(128);
return 0;
}
static int die_err(const char* msg) {
return die("%s: %s", msg, strerror(errno));
}
This diff is collapsed.
{%- set B = xbuildout.encode -%}
dhcp-leasefile={{ directory['etc'] }}/dnsmasq.leases
port=5354
{%- for (ru_ref, iru) in iru_dict|dictsort | selectattr('1._.cpri_link', 'defined') %}
{%- set ru = iru['_'] %}
{%- set ru_tap = ru.cpri_link._tap %}
{%- set vtap = json_module.loads(vtap_jdict[ru_tap]) %}
{%- set plen = netaddr.IPNetwork(vtap.network).prefixlen %}
# {{ B(ru_ref) }} @ {{ ru_tap }}
{#- TODO consider using /128 as we give only 1 address to RU #}
dhcp-range=tag:{{ ru_tap }},{{ vtap.gateway }},{{ vtap.gateway }},static,{{ max(plen,64) }},5m
dhcp-host={{ ru.mac_addr }},tag:{{ ru_tap }},[{{ vtap.gateway }}]
# option 17 used for RU callhome
# dhcp-option=option6:17,[{{ vtap.addr }}]
{%- endfor %}
log-queries
log-dhcp
log-facility={{ directory['home'] }}/var/log/dnsmasq.log
enable-ra
ra-param=adv-send-advert
ra-param=adv-managed-flag
ra-param=adv-other-config-flag
ra-param=adv-autonomous
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Radio Unit",
"type": "object",
"oneOf": [
{ "$ref": "sdr/input-schema.json" },
{ "$ref": "lopcomm/input-schema.json" },
{ "$ref": "sunwave/input-schema.json" }
]
}
This diff is collapsed.
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<processing-elements xmlns="urn:o-ran:processing-element:1.0">
<transport-session-type>CPRI-INTERFACE</transport-session-type>
<ru-elements>
<name>PE0</name>
<transport-flow>
<interface-name>eth1</interface-name>
</transport-flow>
</ru-elements>
</processing-elements>
</config>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "Values returned by Radio Unit instantiation (stub)",
"type": "object",
"properties": {}
}
# ru/sdr/buildout.cfg provides software code for handling SDR Radio Units.
[ru_sdr_libinstance.jinja2.cfg]
<= download-base
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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