Commit 18be4815 authored by Joanne Hugé's avatar Joanne Hugé

software/ors-amarisoft: add support for IMS

Some phones with Android 12+ disconnects from
5G networks which don't support IMS. Therefore
we add minimal IMS support in this commit (even
though we don't actually need it's features).

Only Amarisoft >= 2024-05-02 support launching
lteims without root privilege, so if Amarisoft
version is older IMS is disabled and we inform
the user so in the connection parameters.

For this to work, SIM cards config needs to be
modified, impu and impi must be for instance:
impu: 001010000001312,
impi: 001010000001312@ims.mnc001.mcc001.3gppnetwork.org
parent df7840d1
......@@ -3,22 +3,23 @@
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
* enb: needs to contain libraries from trx_sdr
* trx_sdr
* mme
* mme: needs to contain libraries from libs folder
2. Install ors playbook
3. Deploy this SR
## Services
We run 2 binaries from Amarisoft LTE stack:
We run 3 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
* **lteims** - IP Multimedia Subsystem, for support of VoNR / VoLTE (only for amarisoft > 2024-05-02)
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.
screen because then we cannot easily control their resource usage. Thus we make 3 on-watch services.
### ENB / GNB
......
......@@ -16,7 +16,7 @@
[template]
filename = instance.cfg
md5sum = 43f02b7b3552d0d657fa7dbf43ce20a5
md5sum = 2e30c07c6436895ac0bc6c177cf7013d
[template-ors]
filename = instance-ors.cfg
......@@ -96,7 +96,7 @@ md5sum = 601d6237059fa665d3f3ffb6a78ad9ca
[template-core-network]
_update_hash_filename_ = instance-core-network.jinja2.cfg
md5sum = 326e194e9c98d58d926f89521bb95df5
md5sum = 8e3f5a1a742a6934a61d6a3a282f1293
[template-ue]
_update_hash_filename_ = instance-ue.jinja2.cfg
......@@ -126,9 +126,13 @@ md5sum = 282b11d7b72b01b8325df4632d82b84d
filename = config/sib23.jinja2.asn
md5sum = 959523597e29b048e45ebf58f7ea4c5b
[mt_call_qos.jinja2.sdp]
_update_hash_filename_ = config/mt_call_qos.jinja2.sdp
md5sum = 9dbd93036c15c87c6de74b88b34062b6
[mme.jinja2.cfg]
filename = config/mme.jinja2.cfg
md5sum = 25ae6b1022548183293f0ef0c54532a7
md5sum = 4628509e89747cf30e85ce2cb3a0aebd
[dnsmasq-core-network.jinja2.cfg]
filename = config/dnsmasq-core-network.jinja2.cfg
......@@ -140,7 +144,7 @@ md5sum = 95f4f8fb85e0480eb3e9059b9db26540
[ims.jinja2.cfg]
filename = config/ims.jinja2.cfg
md5sum = 36281b03597252cf75169417d02fc28c
md5sum = f07c85916bcb7e4002c8edc3d087c1be
[ue.jinja2.cfg]
filename = config/ue.jinja2.cfg
......
Changelog
=========
Version 1.0.361 (2024-05-29)
-------------
* Support BBU controlling multiple RUs with one or more CPRI boards
* Code refactorization (to support BBUs with multiple RUs)
* Support IMS for Amarisoft >= 2024-05-02, which is needed for 5G support on some phones
* Add high UL TDD config (TDD CONFIG 4, supported on more UEs than the maximum UL TDD config)
* Add fixed-ips option for core network
Version 1.0.344 (2023-11-03)
-------------
......
{%- set tun_ipv6_addr = slap_configuration.get('tun-ipv6-addr', '2001:db8::1') %}
{%- set tun_ipv6_network = slap_configuration.get('tun-ipv6-network', '2001:db8::/55') %}
{%- set tun_ipv4_addr = slap_configuration.get('tun-ipv4-addr', '172.17.0.1') %}
{%- set tun_ipv4_network = slap_configuration.get('tun-ipv4-network', '172.17.0.0/17') %}
{%- set tun_name = slap_configuration.get('tun-name', 'slaptun0') %}
{%- set tun_ipv6_start = int(netaddr.IPAddress(tun_ipv6_addr)) %}
{%- set tun_ipv6_end = netaddr.IPNetwork(tun_ipv6_network).last %}
{%- set tun_ipv4_start = int(netaddr.IPAddress(tun_ipv4_addr)) %}
{%- set tun_ipv4_end = netaddr.IPNetwork(tun_ipv4_network).last %}
{%- set internet_ipv4 = netaddr.IPAddress( tun_ipv4_start ) %}
{%- set ims_ipv4 = netaddr.IPAddress((tun_ipv4_start + tun_ipv4_end) // 2 + 1) %}
{%- set ims_ipv6 = netaddr.IPAddress((tun_ipv6_start + tun_ipv6_end) // 2 ) %}
{
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'] ",#}
{addr: "{{ ims_ipv4 }}", bind_addr: "{{ ims_ipv4 }}", port_min: 10000, port_max: 20000},
"{{ ims_ipv6 }}",
],
mms_server_bind_addr: "{{ netaddr.IPAddress(netaddr.IPNetwork(slap_configuration['tun-ipv4-network']).first) + 1 }}:1111",
mms_server_bind_addr: "{{ internet_ipv4 }}: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'] }}",
domain: "{{ slapparameter_dict.get('ims_domain', 'rapid.space') }}",
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",
......@@ -44,7 +48,10 @@
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",
ipsec_ifname: "{{ tun_name }}-ims",
ipsec_netns: "{{ tun_name }}-ims-netns",
mt_call_sdp_file: "{{ directory['etc'] }}/mt_call_qos.sdp",
ue_db_filename: "{{ directory['var'] }}/lte_ue_ims.db",
}
{%- set tun_name = slap_configuration.get('tun-name', 'slaptun0') %}
{%- set tun_ipv4_addr = slap_configuration.get('tun-ipv4-addr', '172.17.0.1') %}
{%- set tun_ipv6_addr = slap_configuration.get('tun-ipv6-addr', '2001:db8::1') %}
{%- set tun_ipv4_network = slap_configuration.get('tun-ipv4-network', '172.17.0.0/17') %}
{%- set tun_ipv6_network = slap_configuration.get('tun-ipv6-network', '2001:db8::/55') %}
{%- set tun_ipv4_start = int(netaddr.IPAddress(tun_ipv4_addr)) %}
{%- set tun_ipv6_start = int(netaddr.IPAddress(tun_ipv6_addr)) %}
{%- set tun_ipv4_end = netaddr.IPNetwork(tun_ipv4_network).last %}
{%- set tun_ipv6_end = netaddr.IPNetwork(tun_ipv6_network).last %}
{%- set internet_ipv4_start = netaddr.IPAddress( tun_ipv4_start + 1 ) %}
{%- set internet_ipv4_end = netaddr.IPAddress((tun_ipv4_start + tun_ipv4_end) // 2 - 2 ) %}
{%- set internet_ipv6_start = netaddr.IPAddress( tun_ipv6_start + 1 ) %}
{%- set internet_ipv6_end = netaddr.IPAddress((tun_ipv6_start + tun_ipv6_end) // 2 - 1 ) %}
{%- set ims_ipv4_start = netaddr.IPAddress((tun_ipv4_start + tun_ipv4_end) // 2 + 2 ) %}
{%- set ims_ipv4_end = netaddr.IPAddress( tun_ipv4_end - 1 ) %}
{%- set ims_ipv4 = netaddr.IPAddress((tun_ipv4_start + tun_ipv4_end) // 2 + 1 ) %}
{%- set ims_ipv6 = netaddr.IPAddress((tun_ipv6_start + tun_ipv6_end) // 2 ) %}
{%- set ims_ipv6_start = netaddr.IPAddress((tun_ipv6_start + tun_ipv6_end) // 2 ) %}
{%- set ims_ipv6_end = netaddr.IPAddress( tun_ipv6_end - 1 ) %}
{
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) %}
{%- if slapparameter_dict.get('external_enb_gnb', '') %}
{%- if slapparameter_dict.get('use_ipv4', False) %}
gtp_addr: "{{ gtp_addr_v4 }}",
{% else %}
{%- else %}
gtp_addr: "{{ gtp_addr_v6 }}",
{% endif %}
{% else %}
{%- endif %}
{%- else %}
gtp_addr: "{{ slap_configuration['configuration.gtp_addr'] }}",
{% endif %}
{%- endif %}
plmn: "{{ slapparameter_dict.get('core_network_plmn', "00101") }}",
mme_group_id: 32769,
......@@ -26,6 +47,7 @@
],
rx: {
bind_addr: "127.0.1.100",
qci: {audio: 1, video: 2},
},
......@@ -41,38 +63,54 @@
fifteen_bearers: false,
{%- if support_ims == 'True' %}
ims_list: [
{
ims_addr: "{{ slap_configuration['configuration.ims_addr'] }}",
bind_addr: "{{ slap_configuration['configuration.ims_bind'] }}"
bind_addr: "{{ slap_configuration['configuration.ims_bind'] }}",
}
],
{%- endif %}
pdn_list: [
{
{% if slap_configuration.get('tun-ipv6-network', '') %}
access_point_name: ["default", "internet", "sos"],
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 %}
tun_ifname: "{{ tun_name }}",
first_ip_addr: "{{ internet_ipv4_start }}",
last_ip_addr: "{{ internet_ipv4_end }}",
first_ipv6_prefix: "{{ internet_ipv6_start }}",
last_ipv6_prefix: "{{ internet_ipv6_end }}",
{%- if slapparameter_dict.get('local_domain', '') %}
dns_addr: ["{{ 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 %}
{%- 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",
},
],
},
{%- if support_ims == 'True' %}
{
access_point_name: "ims",
pdn_type: "ipv4v6",
tun_ifname: "{{ tun_name }}-1",
first_ip_addr: "{{ ims_ipv4_start }}",
last_ip_addr: "{{ ims_ipv4_end }}",
first_ipv6_prefix: "{{ ims_ipv6_start }}",
last_ipv6_prefix: "{{ ims_ipv6_end }}",
p_cscf_addr: ["{{ ims_ipv4 }}", "{{ ims_ipv6 }}"],
{%- if slapparameter_dict.get('local_domain', '') %}
dns_addr: ["{{ tun_ipv4_addr }}"],
{%- else %}
dns_addr: ["8.8.8.8", "2001:4860:4860::8888"],
{%- endif %}
erabs: [
{
......@@ -83,6 +121,7 @@
},
],
},
{%- endif %}
],
tun_setup_script: "{{ ifup_empty }}",
......
v=0
o=Amarisoft-IMS 0 0 IN IP4 0.0.0.0
s=Amarisoft-IMS
c=IN IP4 0.0.0.0
t=0 0
m=audio 10000 RTP/AVP 116
c=IN IP4 0.0.0.0
b=AS:41
b=RR:0
b=RS:0
a=rtpmap:116 AMR-WB/16000/1
a=fmtp:116 mode-change-capability=2; max-red=0
a=curr:qos local none
a=curr:qos remote none
a=des:qos mandatory local sendrecv
a=des:qos mandatory remote sendrecv
a=ptime:20
a=maxptime:220
a=sendrecv
{%- if lte_version|replace("-", "")|int < 20240502 %}
{%- set support_ims = false %}
{%- else %}
{%- set support_ims = true %}
{%- endif %}
{%- set dns_slave_instance_list = [] %}
{%- set sim_slave_instance_list = [] %}
{%- set fixed_ip = slapparameter_dict.get("fixed_ips", False) %}
......@@ -70,6 +76,11 @@ parts =
directory
mme-config
mme-service
ims-config
mt-call-config
{%- if support_ims %}
ims-service
{%- endif %}
monitor-base
check-interface-up.py
publish-connection-information
......@@ -135,25 +146,34 @@ 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
[ims-sh-wrapper]
recipe = slapos.recipe.template
output = ${directory:bin}/${:_buildout_section_name_}
ims-log = ${directory:log}/ims-output.log
inline =
#!/bin/sh
{% if not slapparameter_dict.get("testing", False) %}
(echo && echo && date "+[%Y/%m/%d %T.%N %Z] Starting IMS software..." && echo) >> ${:ims-log};
tail -c 1M ${:ims-log} > ${:ims-log}.tmp;
mv ${:ims-log}.tmp ${:ims-log};
{{ ims }}/lteims ${directory:etc}/ims.cfg >> ${:ims-log} 2>> ${:ims-log};
{% endif %}
### IMS
[ims-service]
recipe = slapos.cookbook:wrapper
command-line = {{ mme }}/lteims ${directory:etc}/ims.cfg
command-line = ${ims-sh-wrapper:output}
wrapper-path = ${directory:service}/ims
mode = 0775
pidfile = ${directory:run}/ims.pid
hash-files =
${ims-config:output}
${mt-call-config:output}
${ue-db-config:output}
environment = AMARISOFT_PATH=/opt/amarisoft/.amarisoft
${ims-sh-wrapper:output}
environment =
LD_LIBRARY_PATH={{ openssl_location }}/lib:{{ nghttp2_location }}/lib
AMARISOFT_PATH=/opt/amarisoft/.amarisoft
[mme-sh-wrapper]
recipe = slapos.recipe.template
......@@ -162,6 +182,7 @@ mme-log = ${directory:log}/mme-output.log
inline =
#!/bin/sh
{% if not slapparameter_dict.get("testing", False) %}
sudo -n /opt/amarisoft/init-mme;
rm -f ${directory:var}/lte_ue.db;
(echo && echo && date "+[%Y/%m/%d %T.%N %Z] Starting MME software..." && echo) >> ${:mme-log};
tail -c 1M ${:mme-log} > ${:mme-log}.tmp;
......@@ -215,6 +236,7 @@ config-port = ${iperf-service:port}
[config-base]
recipe = slapos.recipe.template:jinja2
extensions = jinja2.ext.do
extra-context =
context =
section directory directory
section slap_configuration slap-configuration
......@@ -223,12 +245,18 @@ context =
raw gtp_addr_v4 {{ lan_ipv4 }}
import netaddr netaddr
key ifup_empty mme-ifup-empty:wrapper-path
${:extra-context}
[ims-config]
<= config-base
url = {{ ims_template }}
output = ${directory:etc}/ims.cfg
[mt-call-config]
<= config-base
url = {{ mt_call_template }}
output = ${directory:etc}/mt_call_qos.sdp
[ue-db-config]
<= config-base
url = {{ ue_db_template }}
......@@ -245,6 +273,8 @@ url = ${mme-config-dl:target}
url = {{ mme_template }}
{% endif %}
output = ${directory:etc}/mme.cfg
extra-context =
raw support_ims {{ support_ims }}
{% if slapparameter_dict.get("local_domain", '') %}
[dnsmasq-config]
......@@ -289,6 +319,11 @@ password = {{ slapparameter_dict['monitor-password'] | string }}
[publish-connection-information]
<= monitor-publish
recipe = slapos.cookbook:publish.serialised
{%- if support_ims %}
ims = Enabled
{%- else %}
ims = Unsupported (Amarisoft version >= 2024-05-02 is required), 5G may not work with your UE
{%- endif %}
core-network-ipv6 = {{ my_ipv6 }}
core-network-ipv4 = {{ lan_ipv4 }}
amarisoft-version = {{ lte_version }}
......
......@@ -91,7 +91,7 @@ init =
options['sdr'] = path + "/trx_sdr"
options['enb'] = path + "/enb"
options['mme'] = path + "/mme"
options['ims'] = path + "/ims"
options['ims'] = path + "/mme"
options['ue'] = path + "/ue"
import os
lte_expiration = "Unknown"
......@@ -187,10 +187,13 @@ extra-context =
key lte_version amarisoft:lte-version
key lte_expiration amarisoft:lte-expiration
key mme amarisoft:mme
key ims amarisoft:ims
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 mt_call_template ${mt_call_qos.jinja2.sdp:target}
raw netcapdo ${netcapdo:exe}
raw openssl_location ${openssl:location}
raw nghttp2_location ${nghttp2:location}
raw iperf3_location ${iperf3:location}
......
......@@ -35,6 +35,7 @@ parts +=
drb_lte.jinja2.cfg
drb_nr.jinja2.cfg
sib23.jinja2.asn
mt_call_qos.jinja2.sdp
monitor-httpd-extra-conf
# copy all gadget file
gadget
......@@ -114,6 +115,8 @@ filename = enb.jinja2.cfg
[sib23.jinja2.asn]
<= copy-config-to-instance
filename = sib23.jinja2.asn
[mt_call_qos.jinja2.sdp]
<= copy-config-to-instance
[ue_db.jinja2.cfg]
<= copy-config-to-instance
filename = ue_db.jinja2.cfg
......
......@@ -412,7 +412,7 @@ forbid-download-cache = true
[slapos-repository]
<= git-clone-repository
repository = https://lab.nexedi.com/nexedi/slapos.git
branch = master
branch = ors-ims
[template]
recipe = slapos.recipe.template:jinja2
......
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